linux 显示器驱动,基于S3C6410平台 - Linux中LCD设备驱动_Linux编程_Linux公社-Linux系统门户网站...

上一篇说了framebuffer帧缓冲的有关知识,这一篇具体的说下LCD驱动的实现。

1、LCD设备驱动在linux内核中是作为平台设备存在,所以又要说那些已经说过很多遍的东西。

int __devinit s3cfb_init(void)

{

return platform_driver_register(&s3cfb_driver);

}

static void __exit s3cfb_cleanup(void)

{

platform_driver_unregister(&s3cfb_driver);

}

module_init(s3cfb_init);

module_exit(s3cfb_cleanup);

对应的platform_driver结构体为:

static struct platform_driver s3cfb_driver = {

.probe= s3cfb_probe,

.remove= s3cfb_remove,

.suspend= s3cfb_suspend,

.resume= s3cfb_resume,

.driver= {

.name= "s3c-lcd",

.owner= THIS_MODULE,

},

};

那么平台设备的资源呢?

/* LCD Controller */

static u64 s3c_device_lcd_dmamask = 0xffffffffUL;

struct platform_device s3c_device_lcd = {

.name = "s3c-lcd",

.id = -1,设备编号,-1表示只有这样一个设备

.num_resources = ARRAY_SIZE(s3c_lcd_resource),

.resource = s3c_lcd_resource,

.dev              = {

.dma_mask= &s3c_device_lcd_dmamask,

.coherent_dma_mask= 0xffffffffUL

}

};

static struct resource s3c_lcd_resource[] = {

[0] = {

.start = S3C64XX_PA_LCD,  //LCD的I/O内存的开始位置

.end   = S3C64XX_PA_LCD + SZ_1M - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_LCD_VSYNC,    //LCD的开始中断号

.end   = IRQ_LCD_SYSTEM,  //LCD的结束中断号

.flags = IORESOURCE_IRQ,

}

};

2、分析其probe函数,源码如下:

/*

*  Probe

*/

static int __init s3cfb_probe(struct platform_device *pdev)

{

struct resource *res;

struct fb_info *fbinfo;

s3cfb_info_t *info;

char driver_name[] = "s3cfb";

int index = 0, ret, size;

fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);申请一个s3cfb_info_t结构体的空间

if (!fbinfo)

return -ENOMEM;

platform_set_drvdata(pdev, fbinfo);

info = fbinfo->par;

info->dev = &pdev->dev;  填充info结构体变量的相应信息

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);获取LCD平台设备所使用的I/O端口资源。

if (res == NULL) {

dev_err(&pdev->dev, "failed to get memory registers\n");

ret = -ENXIO;

goto dealloc_fb;

}

size = (res->end - res->start) + 1;

info->mem = request_mem_region(res->start, size, pdev->name);申请LCD设备所占的I/O空间

if (info->mem == NULL) {

dev_err(&pdev->dev, "failed to get memory region\n");

ret = -ENOENT;

goto dealloc_fb;

}

info->io = ioremap(res->start, size);将LCD的I/O端口所占用的这段I/O空间映射到内存的虚拟地址。

if (info->io == NULL) {

dev_err(&pdev->dev, "ioremap() of registers failed\n");

ret = -ENXIO;

goto release_mem;

}

s3cfb_pre_init();这个函数的源码在S3cfb_fimd4x.c (linux2.6.28\drivers\video\samsung)文件中,如下所示:

void s3cfb_pre_init(void)

{

/* initialize the fimd specific */

s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;

s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;

s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;

writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);

}

这个函数中涉及到一个结构体s3cfb_fimd_info_t s3cfb_fimd,和这个函数在同一个文件中定义,列出部分源码:

s3cfb_fimd_info_t s3cfb_fimd = {

.vidcon0 = S3C_VIDCON0_INTERLACE_F_PROGRESSIVE | S3C_VIDCON0_VIDOUT_RGB_IF | S3C_VIDCON0_L1_DATA16_SUB_16_MODE | \

S3C_VIDCON0_L0_DATA16_MAIN_16_MODE | S3C_VIDCON0_PNRMODE_RGB_P | \

S3C_VIDCON0_CLKVALUP_ALWAYS | S3C_VIDCON0_CLKDIR_DIVIDED | S3C_VIDCON0_CLKSEL_F_HCLK | \

S3C_VIDCON0_ENVID_DISABLE | S3C_VIDCON0_ENVID_F_DISABLE,

.dithmode = (S3C_DITHMODE_RDITHPOS_5BIT | S3C_DITHMODE_GDITHPOS_6BIT | S3C_DITHMODE_BDITHPOS_5BIT ) & S3C_DITHMODE_DITHERING_DISABLE,

#if defined (CONFIG_FB_S3C_BPP_8)

.wincon0 =  S3C_WINCONx_BYTSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_8BPP_PAL,

.wincon1 =  S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1,

.bpp = S3CFB_PIXEL_BPP_8,

.bytes_per_pixel = 1,

.wpalcon = S3C_WPALCON_W0PAL_16BIT,

..........

..........

.vidosd1c = S3C_VIDOSDxC_ALPHA1_B(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_G(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_R(S3CFB_MAX_ALPHA_LEVEL),

.vidosd2c = S3C_VIDOSDxC_ALPHA1_B(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_G(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_R(S3CFB_MAX_ALPHA_LEVEL),

.vidosd3c = S3C_VIDOSDxC_ALPHA1_B(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_G(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_R(S3CFB_MAX_ALPHA_LEVEL),

.vidosd4c = S3C_VIDOSDxC_ALPHA1_B(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_G(S3CFB_MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_R(S3CFB_MAX_ALPHA_LEVEL),

.vidintcon0 = S3C_VIDINTCON0_FRAMESEL0_VSYNC | S3C_VIDINTCON0_FRAMESEL1_NONE | S3C_VIDINTCON0_INTFRMEN_DISABLE | \

S3C_VIDINTCON0_FIFOSEL_WIN0 | S3C_VIDINTCON0_FIFOLEVEL_25 | S3C_VIDINTCON0_INTFIFOEN_DISABLE | S3C_VIDINTCON0_INTEN_ENABLE,

.vidintcon1 = 0,

.xoffset = 0,

.yoffset = 0,

.w1keycon0 = S3C_WxKEYCON0_KEYBLEN_DISABLE | S3C_WxKEYCON0_KEYEN_F_DISABLE | S3C_WxKEYCON0_DIRCON_MATCH_FG_IMAGE | S3C_WxKEYCON0_COMPKEY(0x0),

.............

.w4keycon1 = S3C_WxKEYCON1_COLVAL(0xffffff),

.sync = 0,

.cmap_static = 1,

.vs_offset = S3CFB_DEFAULT_DISPLAY_OFFSET,

.brightness = S3CFB_DEFAULT_BRIGHTNESS,

.backlight_level = S3CFB_DEFAULT_BACKLIGHT_LEVEL,

.backlight_power = 1,

.lcd_power = 1,

};

那么对应的结构体原型在哪呢?

在S3cfb.h (linux2.6.28\drivers\video\samsung)文件中,如下所示:

看那些对应的注释,也应该大致明白这个结构体的作用,存储与显示控制器有关的信息,还有显示屏幕的信息。不知道大家对s3cfb_fimd_info_t这个结构体的命名有何看法?名字往往代表了这个结构体的作用。其实这个结构体的名字给我们的信息是:

fimd—   ——    ——

FIMD:Fully Interactive Mobile Display (完全交互式移动显示设备)

这是第一个概念,另一个概念是OSD,我查了下资料,有这样的含义:

OSD是on-screen display的简称,即屏幕菜单式调节方式。一般是按Menu键后屏幕弹出的显示器各项调节项目信息的矩形菜单,可通过该菜单对显示器各项工作指标包括色彩、模式、几何形状等进行调整,从而达到最佳的使用状态。

现在对这个结构体的认识是不是深刻多了?

typedef struct {

/* Screen size */

int width;

int height;

/* Screen info */

int xres;

int yres;

/* Virtual Screen info */

int xres_virtual;

int yres_virtual;

int xoffset;

int yoffset;

/* OSD Screen size */

int osd_width;

int osd_height;

/* OSD Screen info */

int osd_xres;

int osd_yres;

/* OSD Screen info */

int osd_xres_virtual;

int osd_yres_virtual;

int bpp;

int bytes_per_pixel;

unsigned long pixclock;

int hsync_len;

int left_margin;

int right_margin;

int vsync_len;

int upper_margin;

int lower_margin;

int sync;

int cmap_grayscale:1;

int cmap_inverse:1;

int cmap_static:1;

int unused:29;

/* backlight info */

int backlight_min;

int backlight_max;

int backlight_default;

int vs_offset;

int brightness;

int palette_win;

int backlight_level;

int backlight_power;

int lcd_power;

s3cfb_vsync_info_t vsync_info;

s3cfb_vs_info_t vs_info;

/* lcd configuration registers */

unsigned long lcdcon1;

unsigned long lcdcon2;

unsigned long lcdcon3;

unsigned long lcdcon4;

unsigned long lcdcon5;

/* GPIOs */

unsigned long gpcup;

unsigned long gpcup_mask;

unsigned long gpccon;

unsigned long gpccon_mask;

unsigned long gpdup;

unsigned long gpdup_mask;

unsigned long gpdcon;

unsigned long gpdcon_mask;

/* lpc3600 control register */

unsigned long lpcsel;

unsigned long lcdtcon1;

unsigned long lcdtcon2;

unsigned long lcdtcon3;

unsigned long lcdosd1;

unsigned long lcdosd2;

unsigned long lcdosd3;

unsigned long lcdsaddrb1;

unsigned long lcdsaddrb2;

unsigned long lcdsaddrf1;

unsigned long lcdsaddrf2;

unsigned long lcdeaddrb1;

unsigned long lcdeaddrb2;

unsigned long lcdeaddrf1;

unsigned long lcdeaddrf2;

unsigned long lcdvscrb1;

unsigned long lcdvscrb2;

unsigned long lcdvscrf1;

unsigned long lcdvscrf2;

unsigned long lcdintcon;

unsigned long lcdkeycon;

unsigned long lcdkeyval;

unsigned long lcdbgcon;

unsigned long lcdfgcon;

unsigned long lcddithcon;

unsigned long vidcon0;

unsigned long vidcon1;

unsigned long vidtcon0;

unsigned long vidtcon1;

unsigned long vidtcon2;

unsigned long vidtcon3;

unsigned long wincon0;

unsigned long wincon2;

unsigned long wincon1;

unsigned long wincon3;

unsigned long wincon4;

unsigned long vidosd0a;

unsigned long vidosd0b;

unsigned long vidosd0c;

unsigned long vidosd1a;

unsigned long vidosd1b;

unsigned long vidosd1c;

unsigned long vidosd1d;

unsigned long vidosd2a;

unsigned long vidosd2b;

unsigned long vidosd2c;

unsigned long vidosd2d;

unsigned long vidosd3a;

unsigned long vidosd3b;

unsigned long vidosd3c;

unsigned long vidosd4a;

unsigned long vidosd4b;

unsigned long vidosd4c;

unsigned long vidw00add0b0;

unsigned long vidw00add0b1;

unsigned long vidw01add0;

unsigned long vidw01add0b0;

unsigned long vidw01add0b1;

unsigned long vidw00add1b0;

unsigned long vidw00add1b1;

unsigned long vidw01add1;

unsigned long vidw01add1b0;

unsigned long vidw01add1b1;

unsigned long vidw00add2b0;

unsigned long vidw00add2b1;

unsigned long vidw02add0;

unsigned long vidw03add0;

unsigned long vidw04add0;

unsigned long vidw02add1;

unsigned long vidw03add1;

unsigned long vidw04add1;

unsigned long vidw00add2;

unsigned long vidw01add2;

unsigned long vidw02add2;

unsigned long vidw03add2;

unsigned long vidw04add2;

unsigned long vidintcon;

unsigned long vidintcon0;

unsigned long vidintcon1;

unsigned long w1keycon0;

unsigned long w1keycon1;

unsigned long w2keycon0;

unsigned long w2keycon1;

unsigned long w3keycon0;

unsigned long w3keycon1;

unsigned long w4keycon0;

unsigned long w4keycon1;

unsigned long win0map;

unsigned long win1map;

unsigned long win2map;

unsigned long win3map;

unsigned long win4map;

unsigned long wpalcon;

unsigned long dithmode;

unsigned long intclr0;

unsigned long intclr1;

unsigned long intclr2;

unsigned long win0pal;

unsigned long win1pal;

/* utility functions */

void (*set_backlight_power)(int);

void (*set_lcd_power)(int);

void (*set_brightness)(int);

int (*map_video_memory)(s3cfb_info_t *);

int (*unmap_video_memory)(s3cfb_info_t *);

}s3cfb_fimd_info_t;

下一篇接着从这里分析:

s3cfb_set_backlight_power(1);

s3cfb_set_lcd_power(1);

s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL);

info->clk = clk_get(NULL, "lcd");

if (!info->clk || IS_ERR(info->clk)) {

printk(KERN_INFO "failed to get lcd clock source\n");

ret =  -ENOENT;

goto release_io;

}

clk_enable(info->clk);

printk("S3C_LCD clock got enabled :: %ld.%03ld Mhz\n", PRINT_MHZ(clk_get_rate(info->clk)));

s3cfb_fimd.vsync_info.count = 0;

init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

if (res == NULL) {

dev_err(&pdev->dev, "failed to get irq\n");

ret = -ENXIO;

goto release_clock;

}

ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev);

if (ret != 0) {

printk("Failed to install irq (%d)\n", ret);

goto release_clock;

}

msleep(5);

for (index = 0; index < S3CFB_NUM; index++) {

s3cfb_info[index].mem = info->mem;

s3cfb_info[index].io = info->io;

s3cfb_info[index].clk = info->clk;

s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index);

/* Initialize video memory */

ret = s3cfb_map_video_memory(&s3cfb_info[index]);

if (ret) {

printk("Failed to allocate video RAM: %d\n", ret);

ret = -ENOMEM;

goto release_irq;

}

ret = s3cfb_init_registers(&s3cfb_info[index]);

ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb);

if (index < 2){

if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0)

goto dealloc_fb;

} else {

if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)

goto dealloc_fb;

}

ret = register_framebuffer(&s3cfb_info[index].fb);

if (ret < 0) {

printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);

goto free_video_memory;

}

printk(KERN_INFO "fb%d: %s frame buffer device\n", s3cfb_info[index].fb.node, s3cfb_info[index].fb.fix.id);

}

/* create device files */

ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);

if (ret < 0)

printk(KERN_WARNING "s3cfb: failed to add entries\n");

ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);

if (ret < 0)

printk(KERN_WARNING "s3cfb: failed to add entries\n");

ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);

if (ret < 0)

printk(KERN_WARNING "s3cfb: failed to add entries\n");

return 0;

free_video_memory:

s3cfb_unmap_video_memory(&s3cfb_info[index]);

release_irq:

free_irq(res->start, &info);

release_clock:

clk_disable(info->clk);

clk_put(info->clk);

release_io:

iounmap(info->io);

release_mem:

release_resource(info->mem);

kfree(info->mem);

dealloc_fb:

framebuffer_release(fbinfo);

return ret;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值