腾讯微群加入QQ群

 找回密码
 加入我们

!connect_header_login!

!connect_header_login_tip!

搜索
查看: 368|回复: 0

《Linux驱动》iTop4412开发板LCD驱动 详细分析 (二)

[复制链接]
发表于 2016-8-23 13:24:21 | 显示全部楼层 |阅读模式

这里写图片描述


由上图可以看出 lcd的应用层 通过 内核的fbmem接口 再调用驱动xxxfb.c的内容
而fbmem接口是内核提供的,所有驱动设计人员主要的任务就是定义一个fb_info 结构体(该结构由内核提供),然后填充结构体中的内容做好相应的初始化后,提交给内核就可以了。
———————————-
首先驱动文件在: 在kernel/drivers/video/samsung/目录下。我现在用的设备涉及的驱动如下:
这里以itop4412提供的4.3寸WXCAT43屏为参考:
s3cfb_wa101s.c ——设备参数相关文件
s3cfb_fimd6x.c —— 具体平台硬件相关文件
s3cfb_ops.c ——-fb 操作集合
s3cfb_main.c ——-驱动框架
好,首先来,分析s3cfb_main.c ,当然在介绍该.c时,会把之前所有的.c都牵扯进来,毕竟驱动框架调用了其他c文件的接口。(这一节主要介绍probe函数调用的接口功能,接口具体实现在下一节中介绍)

static struct platform_driver s3cfb_driver = {
    .probe      = s3cfb_probe, //探测设备
    .remove     = s3cfb_remove,//设备移除
#ifndef CONFIG_HAS_EARLYSUSPEND 
    .suspend    = s3cfb_suspend,//设备暂定
    .resume     = s3cfb_resume, //设备恢复
#endif
    .driver     = {
        .name   = S3CFB_NAME, //设备名字,在s3cfb.h 当中定义,与device匹配的关键,定义如下
                              //#define S3CFB_NAME      "s3cfb"
        .owner  = THIS_MODULE,
#ifdef CONFIG_EXYNOS_DEV_PD
        .pm = &s3cfb_pm_ops, //pm电源管理集合
#endif
    },
};
static int s3cfb_register(void)
{
    platform_driver_register(&s3cfb_driver); 平台设备的注册
    return 0;
}
static void s3cfb_unregister(void)
{
    platform_driver_unregister(&s3cfb_driver);平台设备的卸载
}
module_init(s3cfb_register);
module_exit(s3cfb_unregister);

s3cfb_probe 是重点 ,现在着重介绍:static int s3cfb_probe(struct platform_device *pdev);
probe函数的主要作用是获取device资源,获取设备资源,初始化设备,注册和使能设备等

static int s3cfb_probe(struct platform_device *pdev)
{
    struct s3c_platform_fb *pdata = NULL; //s3c平台资源结构体
    struct resource *res = NULL; //资源指针
    struct s3cfb_global *fbdev[2]; //lcd driver全局指针结构体指针,是分析驱动的核心指针

#ifdef CONFIG_EXYNOS_DEV_PD
    /* to use the runtime PM helper functions */
    pm_runtime_enable(&pdev->dev);
    /* enable the power domain */
    pm_runtime_get_sync(&pdev->dev);
#endif
#ifndef CONFIG_TC4_EVT
    lcd_regulator = regulator_get(NULL, "vdd33_lcd");  
    regulator_enable(lcd_regulator);    //yulu
#endif
    /*----------------------------------------------*/
            pm_runtime_enable ,pm_runtime_get_sysnc 是运行时电源管理(运行时PM)的支持,是在电源管理的核心(PM core)下借助于以下方式实现的。regular_get ,regular_enable   是电源管理制regulator 机制。现在android/linux为模块设备供电有两种,一种GPIO供电,另一个就是电源管理芯片。电源管理芯片可以为多设备供电,且这些设备电压电流有所同。为这些设备提供的稳压器代码模型即为regulator。
   这里不做详细要求,如有兴趣请查阅相关资料
    /*-----------------------------------------------*/
    fbfimd = kzalloc(sizeof(struct s3cfb_fimd_desc), GFP_KERNEL);//创建fimd 设备描述

    if (FIMD_MAX == 2)// 接入设备dual 判断,这里显然只有一个,这个宏在s3cfb.h 中
        fbfimd->dual = 1;
    else
        fbfimd->dual = 0;

    for (i = 0; i < FIMD_MAX; i++) {//根据要描述的fimd,进行分配空间,初始化等操作
        /* global structure */  //分配全局数据区,通过上面的数据结构体可以很清晰看出来
        fbfimd->fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
        fbdev = fbfimd->fbdev;
        fbdev->dev = &pdev->dev; //让global指向了platform 的设备,也就是
        //上一节中介绍的平台设备描述,struct platform_device s3c_device_fb 里面有设备的io
        //中断资源等

        //这个函数是获取具体设备的参数的,跟s3cfb_wa101s.c有关     
        // 在这个函数中我们看到如何通过硬件拨码开关选择lcd硬件
        //讲在下面介绍
        s3cfb_set_lcd_info(fbdev);

        /* platform_data */
        //通过这个函数获得上一篇中介绍的上s3c_platform_fb
        //现在让我们回顾一下 在dev-fimd-s5p.c 中有 s3cfb_set_platdat 函数中
        /*
            struct s3c_platform_fb *npd;........
            s3cfb_get_clk_name(npd->clk_name);
            npd->cfg_gpio = s3cfb_cfg_gpio;
            npd->backlight_on = s3cfb_backlight_on;
            npd->backlight_off = s3cfb_backlight_off;
            npd->lcd_on = s3cfb_lcd_on;
            npd->lcd_off = s3cfb_lcd_off;
            npd->clk_on = s3cfb_clk_on;
            npd->clk_off = s3cfb_clk_off;
            */
        //现在知道作用了吧  
        pdata = to_fb_plat(&pdev->dev);
        if (pdata->cfg_gpio)
            pdata->cfg_gpio(pdev);//初始化io,将在下面介绍

        if (pdata->clk_on)
            pdata->clk_on(pdev, &fbdev->clock);//初始化时钟
            //将在下面介绍            

        /* io memory */
        //从平台设备中获取io资源,申请io资源,映射io资源
        res = platform_get_resource(pdev, IORESOURCE_MEM, i);
        res = request_mem_region(res->start,
                    res->end - res->start + 1, pdev->name);
        fbdev->regs = ioremap(res->start, res->end - res->start + 1);

        /* irq */ 从平台驱动获取frame中断
        fbdev->irq = platform_get_irq(pdev, 0);
        request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,pdev->name, fbdev)

        // 如有必要获取fifo中断
#ifdef CONFIG_FB_S5P_TRACE_UNDERRUN
        if (request_irq(platform_get_irq(pdev, 1), s3cfb_irq_fifo,IRQF_DISABLED, pdev->name, fbdev)) 
        s3cfb_set_fifo_interrupt(fbdev, 1);
        dev_info(fbdev->dev, "fifo underrun trace\n");
#endif
        /* hw setting */
        /*故名思议这是对硬件的初始化,里面主要是对exynos4412的寄存器设置所有会调到 s3cfb_fimd6x.c 中的寄存器操作,将在下面详细介绍*/
        s3cfb_init_global(fbdev);
        fbdev->system_state = POWER_ON;//设置设备工作状态power on

        /* alloc fb_info */
        /* 这个函数在s3cfb_ops.c 文件中   -------fb 操作集合*/
        /*这个函数的作用是申请struct fb_info 结构体,初始化fb_info 结构体的信息*/
        /*fb_info 结构体 上与内核接口耦合的关系,我们写lcd驱动就是除了初始化相关硬件以外*/
        /*就是把fb_info 结构体初始化后 注册到内核,供 fb_mem 调用,上层才能跟底层结合起来*/
        /*该函数具体内容将在接下来介绍*/
        s3cfb_alloc_framebuffer(fbdev, i); 


        /* register fb_info */
        /*这个函数在s3cfb_ops.c 文件中 主要是向内核注册fb_info ,将在以后介绍*/
        if (s3cfb_register_framebuffer(fbdev)) 

        /* enable display */
        /*s3cfb_set_clock 向VIDCON0 配置相应的时钟参数*/
        s3cfb_set_clock(fbdev);

        /* --------选择windows通道,使能wins窗口,将在接下来*/
        s3cfb_enable_window(fbdev[0], pdata->default_win);
#ifdef CONFIG_FB_S5P_SOFTBUTTON_UI /* Add Menu UI */
        s3cfb_enable_window(fbdev[0], 4);
#endif
        /*设置窗口状态,/* screen: unblanked, hsync: on,  vsync: on */
        s3cfb_update_power_state(fbdev, pdata->default_win,
                    FB_BLANK_UNBLANK);
        /*2.真正使能lcd模块,设置exynos的基础器,所以与硬件有关*/
        /*具体函数在 s3cfb_fimd6x.c 。将在接下来介绍*/
        s3cfb_display_on(fbdev);


        #ifdef CONFIG_FB_S5P_LCD_INIT
        /* panel control */
        if (pdata->backlight_on) //判断是否开启背光
            pdata->backlight_on(pdev);

        if (pdata->lcd_on)  //判断是启动lcd
            pdata->lcd_on(pdev);
        #endif

        /*在/sys/class/下创建一个属性文件 okprobe 函数就此结束*/   
        ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
    return 0;
}

probe函数的主要作用和流程:

  1. 获取平台设备 device中的资源
  2. 对设备做了一下相应的初始化
  3. 申请了fb_info ,根据要求进行了填充
  4. 向内核提交了fb_info
  5. 使能设备等
  6. 创建属性文件

这是probe功能,remove是做相应的逆操作.

在上面的介绍中是只有简单介绍了probe中主要有哪些函数和一些功能,
那么在下一节中将会介绍,这些函数的具体实现和原理

0
0

转自:http://blog.csdn.net/HERGhost/article/details/51458854?locationNum=7
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

QQ|手机版|Archiver|小黑屋|一起疯|苦咖啡 ( 新ICP备12000197号  

GMT+8, 2018-1-21 14:56 , Processed in 0.052513 second(s), 11 queries , Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表