LCD(四)平台设备驱动之 platform_driver

S5PV210 LCD platform_driver 的实例 s3cfb_driver 定义在 drivers/video/samsung/s3cfb.c中

static struct platform_driver s3cfb_driver = {
	.probe = s3cfb_probe,
	.remove = __devexit_p(s3cfb_remove),
	.driver = {
		   .name = "s5pv210-lcd", //要与平台驱动相同
		   .owner = THIS_MODULE,
	},
};
并在模块加载时注册,模块卸载时注销,如下:
static int __init s3cfb_register(void)
{
	platform_driver_register(&s3cfb_driver);

	return 0;
}
static void __exit s3cfb_unregister(void)
{
	platform_driver_unregister(&s3cfb_driver);
}
探测函数s3cfb_probe如下:
static int __devinit s3cfb_probe(struct platform_device *pdev)
{
	struct s3c_platform_fb *pdata = NULL;//s3c平台资源结构体(配置信息)
        struct s3cfb_global *fbdev;//lcd driver全局变量结构体指针,是分析驱动的核心指针
        struct resource *res = NULL;//资源指针,用来保存冲LCD平台设备中获取的LCD资源
	int i, j, ret = 0;
     
	fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);//创建设备描述
	if (!fbdev) {
		dev_err(fbdev->dev, "failed to allocate for "
			"global fb structure\n");
		ret = -ENOMEM;
		goto err_global;
	}
	fbdev->dev = &pdev->dev; //获取平台设备s5p_device_lcd 
	
        fbdev->regulator = regulator_get(&pdev->dev, "pd");
//	if (!fbdev->regulator) {
	if (IS_ERR(fbdev->regulator)) {
		dev_err(fbdev->dev, "failed to get regulator\n");
		ret = -EINVAL;
		goto err_regulator;
	}

	ret = regulator_enable(fbdev->regulator);
	if (ret < 0) {
		dev_err(fbdev->dev, "failed to enable regulator\n");
		ret = -EINVAL;
		goto err_regulator;
	}


#if RITESH
	fbdev->vcc_lcd = regulator_get(&pdev->dev, "vcc_lcd");
	if (!fbdev->vcc_lcd) {
		dev_err(fbdev->dev, "failed to get vcc_lcd\n");
		ret = -EINVAL;
		goto err_vcc_lcd;
	}
	ret = regulator_enable(fbdev->vcc_lcd);
	if (ret < 0) {
		dev_err(fbdev->dev, "failed to enable vcc_lcd\n");
		ret = -EINVAL;
		goto err_vcc_lcd;
	}

	fbdev->vlcd = regulator_get(&pdev->dev, "vlcd");
	if (!fbdev->vlcd) {
		dev_err(fbdev->dev, "failed to get vlcd\n");
		ret = -EINVAL;
		goto err_vlcd;
	}
	ret = regulator_enable(fbdev->vlcd);
	if (ret < 0) {
		dev_err(fbdev->dev, "failed to enable vlcd\n");
		ret = -EINVAL;
		goto err_vlcd;
	}
#endif
	pdata = to_fb_plat(&pdev->dev);  //获取平台设备的LCD参数信息 Platform data:EmbedSky_LCD_fb_data
	if (!pdata) {
		dev_err(fbdev->dev, "failed to get platform data\n");
		ret = -EINVAL;
		goto err_pdata;
	}

	fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd; //得到A70_TN92

        //配置GPIO端口
        if (pdata->cfg_gpio)
		pdata->cfg_gpio(pdev); //执行EmbedSky_LCD_fb_dataEmbedSky_LCD_cfg_gpio函数配置相关寄存器

        //设置时钟参数
	if (pdata->clk_on)
		pdata->clk_on(pdev, &fbdev->clock); //即arch/arm/mach-s5pv210/setup-fb.c 中s3cfb_clk_on

        /*获取LCD平台设备的资源s3cfb_resource, 这个IORESOURCE_MEM要与平台设备中定义一致*/
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(fbdev->dev, "failed to get io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}
        
        /*申请IO空间*/
        //申请LCD IO端口所占用的IO空间(注意理解IO空间和内存空间的区别),request_mem_region定义在ioport.h中         
        res = request_mem_region(res->start,
		res->end - res->start + 1, pdev->name);
	if (!res) {
		dev_err(fbdev->dev, "failed to request io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}

        /*映射IO空间*/
        /*将LCD的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中
        * 注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作*/
        fbdev->regs = ioremap(res->start, res->end - res->start + 1);
	if (!fbdev->regs) {
		dev_err(fbdev->dev, "failed to remap io region\n");
		ret = -EINVAL;
		goto err_mem;
	}

        //设置VSYNC中断
	s3cfb_set_vsync_interrupt(fbdev, 1);
        //设置全局中断
	s3cfb_set_global_interrupt(fbdev, 1);
        
        /*初始化LCD参数,包括LCD大小、时序、极性*/
        s3cfb_init_global(fbdev);
        
        /*申请framebuffer显示缓存区*/
        if (s3cfb_alloc_framebuffer(fbdev)) {
		ret = -ENOMEM;
		goto err_alloc;
	}

        /*framebuffer设备注册*/
	if (s3cfb_register_framebuffer(fbdev)) {
		ret = -EINVAL;
		goto err_register;
	}

	s3cfb_set_clock(fbdev);
	s3cfb_set_window(fbdev, pdata->default_win, 1);

	s3cfb_display_on(fbdev);

        /*获取设备中断*/
	fbdev->irq = platform_get_irq(pdev, 0);
	if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,
			pdev->name, fbdev)) {
		dev_err(fbdev->dev, "request_irq failed\n");
		ret = -EINVAL;
		goto err_irq;
	}

#ifdef CONFIG_FB_S3C_LCD_INIT
//#if defined(CONFIG_FB_S3C_TL2796)
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);
//#endif
	if (!bootloaderfb && pdata->reset_lcd)
		pdata->reset_lcd(pdev);
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
	fbdev->early_suspend.suspend = s3cfb_early_suspend;
	fbdev->early_suspend.resume = s3cfb_late_resume;
	fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
	register_early_suspend(&fbdev->early_suspend);
#endif

        /*添加到sysfs文件系统,创建fb设备文件*/
	ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
	if (ret < 0)
		dev_err(fbdev->dev, "failed to add sysfs entries\n");

	dev_info(fbdev->dev, "registered successfully\n");
   if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {
                printk("Start display and show logo\n");
                /* Start display and show logo on boot */
                fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]);
                fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);
        }

        //Jerry Gou ++
        mdelay(200);
        if (pdata->backlight_on)
                pdata->backlight_on(pdev); //开启背光 对应ek070tn93_fb_data的 ek070tn93_backlight_on
       //++end

        return 0;

err_irq:
	s3cfb_display_off(fbdev);
	s3cfb_set_window(fbdev, pdata->default_win, 0);
	for (i = pdata->default_win;
			i < pdata->nr_wins + pdata->default_win; i++) {
		j = i % pdata->nr_wins;
		unregister_framebuffer(fbdev->fb[j]);
	}
err_register:
	for (i = 0; i < pdata->nr_wins; i++) {
		if (i == pdata->default_win)
			s3cfb_unmap_default_video_memory(fbdev->fb[i]);
		framebuffer_release(fbdev->fb[i]);
	}
	kfree(fbdev->fb);

err_alloc:
	iounmap(fbdev->regs);

err_mem:
	release_mem_region(res->start,
				 res->end - res->start + 1);

err_io:
	pdata->clk_off(pdev, &fbdev->clock);

err_pdata:
	regulator_disable(fbdev->vlcd);

err_vlcd:
	regulator_disable(fbdev->vcc_lcd);

err_vcc_lcd:
	regulator_disable(fbdev->regulator);

err_regulator:
	kfree(fbdev);

err_global:
	return ret;
}



猜你喜欢

转载自blog.csdn.net/jerrygou/article/details/80112754
今日推荐