Linux LCD驱动分析

硬件平台:mini2440 + TD035STED4  软件平台:linux-2.6.32.2 日期:2012/07/04

首先看驱动模块的初始化函数:

/* drivers/video/s3c2410fb.c */

   1119 int __init s3c2410fb_init(void)
   1120 {
   1121         int ret = platform_driver_register(&s3c2410fb_driver);
   1122
   1123         if (ret == 0)
   1124                 ret = platform_driver_register(&s3c2412fb_driver);
   1125
   1126         return ret;
   1127 }
   1128
   1129 static void __exit s3c2410fb_cleanup(void)
   1130 {
   1131         platform_driver_unregister(&s3c2410fb_driver);
   1132         platform_driver_unregister(&s3c2412fb_driver);
   1133 }


初始化函数里面就注册了一个平台设备驱动。

再来看驱动模块卸载函数:

   1129 static void __exit s3c2410fb_cleanup(void)
   1130 {
   1131         platform_driver_unregister(&s3c2410fb_driver);
   1132         platform_driver_unregister(&s3c2412fb_driver);
   1133 }


卸载函数里面注销平台设备驱动。

s3c2440自然采用的是s3c2410fb_driver,我们来看这个结构的定义:

   1097 static struct platform_driver s3c2410fb_driver = {
   1098         .probe          = s3c2410fb_probe,
   1099         .remove         = s3c2410fb_remove,
   1100         .suspend        = s3c2410fb_suspend,
   1101         .resume         = s3c2410fb_resume,
   1102         .driver         = {
   1103                 .name   = "s3c2410-lcd",
   1104                 .owner  = THIS_MODULE,
   1105         },
   1106 };


我们看driver中的name字段为s3c2410-lcd,那自然去找与之对应的平台设备。

我们在devs.c中找到了这个平台设备的定义:

/* arch/arm/plat-s3c24xx/devs.c */

    141 /* LCD Controller */
    142
    143 static struct resource s3c_lcd_resource[] = {
    144         [0] = {
    145                 .start = S3C24XX_PA_LCD,
    146                 .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
    147                 .flags = IORESOURCE_MEM,
    148         },
    149         [1] = {
    150                 .start = IRQ_LCD,
    151                 .end   = IRQ_LCD,
    152                 .flags = IORESOURCE_IRQ,
    153         }
    154
    155 };
    156
    157 static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
    158
    159 struct platform_device s3c_device_lcd = {
    160         .name             = "s3c2410-lcd",
    161         .id               = -1,
    162         .num_resources    = ARRAY_SIZE(s3c_lcd_resource),
    163         .resource         = s3c_lcd_resource,
    164         .dev              = {
    165                 .dma_mask               = &s3c_device_lcd_dmamask,


    166                 .coherent_dma_mask      = 0xffffffffUL
    167         }
    168 };
    169
    170 EXPORT_SYMBOL(s3c_device_lcd);


平台设备也有了,平台设备注册进了内核之后,那自然会调用驱动中的probe函数。

    815 static char driver_name[] = "s3c2410fb";
    816
    817 static int __init s3c24xxfb_probe(struct platform_device *pdev,
    818                                   enum s3c_drv_type drv_type)
    819 {
    820         struct s3c2410fb_info *info;
    821         struct s3c2410fb_display *display;
    822         struct fb_info *fbinfo;
    823         struct s3c2410fb_mach_info *mach_info;
    824         struct resource *res;
    825         int ret;
    826         int irq;
    827         int i;
    828         int size;
    829         u32 lcdcon1;
    830
    831         mach_info = pdev->dev.platform_data;
    832         if (mach_info == NULL) {
    833                 dev_err(&pdev->dev,
    834                         "no platform data for lcd, cannot attach\n");
    835                 return -EINVAL;
    836         }
    837
    838         if (mach_info->default_display >= mach_info->num_displays) {
    839                 dev_err(&pdev->dev, "default is %d but only %d displays\n",
    840                         mach_info->default_display, mach_info->num_displays);
    841                 return -EINVAL;


    842         }
    843
    844         display = mach_info->displays + mach_info->default_display;
    845
    846         irq = platform_get_irq(pdev, 0);
    847         if (irq < 0) {
    848                 dev_err(&pdev->dev, "no irq for device\n");
    849                 return -ENOENT;
    850         }
    851
    852         fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
    853         if (!fbinfo)
    854                 return -ENOMEM;
    855
    856         platform_set_drvdata(pdev, fbinfo);
    857
    858         info = fbinfo->par;
    859         info->dev = &pdev->dev;
    860         info->drv_type = drv_type;
    861
    862         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    863         if (res == NULL) {
    864                 dev_err(&pdev->dev, "failed to get memory registers\n");
    865                 ret = -ENXIO;
    866                 goto dealloc_fb;


    867         }
    868
    869         size = (res->end - res->start) + 1;
    870         info->mem = request_mem_region(res->start, size, pdev->name);
    871         if (info->mem == NULL) {
    872                 dev_err(&pdev->dev, "failed to get memory region\n");
    873                 ret = -ENOENT;
    874                 goto dealloc_fb;
    875         }
    876
    877         info->io = ioremap(res->start, size);
    878         if (info->io == NULL) {
    879                 dev_err(&pdev->dev, "ioremap() of registers failed\n");
    880                 ret = -ENXIO;
    881                 goto release_mem;
    882         }
    883
    884         info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBAS        E);
    885
    886         dprintk("devinit\n");
    887
    888         strcpy(fbinfo->fix.id, driver_name);
    889
    890         /* Stop the video */
    891         lcdcon1 = readl(info->io + S3C2410_LCDCON1);
    892         writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);


    893
    894         fbinfo->fix.type            = FB_TYPE_PACKED_PIXELS;
    895         fbinfo->fix.type_aux        = 0;
    896         fbinfo->fix.xpanstep        = 0;
    897         fbinfo->fix.ypanstep        = 0;
    898         fbinfo->fix.ywrapstep       = 0;
    899         fbinfo->fix.accel           = FB_ACCEL_NONE;
    900
    901         fbinfo->var.nonstd          = 0;
    902         fbinfo->var.activate        = FB_ACTIVATE_NOW;
    903         fbinfo->var.accel_flags     = 0;
    904         fbinfo->var.vmode           = FB_VMODE_NONINTERLACED;
    905
    906         fbinfo->fbops               = &s3c2410fb_ops;
    907         fbinfo->flags               = FBINFO_FLAG_DEFAULT;
    908         fbinfo->pseudo_palette      = &info->pseudo_pal;
    909
    910         for (i = 0; i < 256; i++)
    911                 info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
    912
    913         ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
    914         if (ret) {
    915                 dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
    916                 ret = -EBUSY;
    917                 goto release_regs;


    918         }
    919
    920         info->clk = clk_get(NULL, "lcd");
    921         if (!info->clk || IS_ERR(info->clk)) {
    922                 printk(KERN_ERR "failed to get lcd clock source\n");
    923                 ret = -ENOENT;
    924                 goto release_irq;
    925         }
    926
    927         clk_enable(info->clk);
    928         dprintk("got and enabled clock\n");
    929
    930         msleep(1);
    931
    932         info->clk_rate = clk_get_rate(info->clk);
    933
    934         /* find maximum required memory size for display */
    935         for (i = 0; i < mach_info->num_displays; i++) {
    936                 unsigned long smem_len = mach_info->displays[i].xres;
    937
    938                 smem_len *= mach_info->displays[i].yres;
    939                 smem_len *= mach_info->displays[i].bpp;
    940                 smem_len >>= 3;
    941                 if (fbinfo->fix.smem_len < smem_len)
    942                         fbinfo->fix.smem_len = smem_len;
    943         }


    944
    945         /* Initialize video memory */
    946         ret = s3c2410fb_map_video_memory(fbinfo);
    947         if (ret) {
    948                 printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
    949                 ret = -ENOMEM;
    950                 goto release_clock;
    951         }
    952
    953         dprintk("got video memory\n");
    954
    955         fbinfo->var.xres = display->xres;
    956         fbinfo->var.yres = display->yres;
    957         fbinfo->var.bits_per_pixel = display->bpp;
    958
    959         s3c2410fb_init_registers(fbinfo);
    960
    961         s3c2410fb_check_var(&fbinfo->var, fbinfo);
    962
    963         ret = s3c2410fb_cpufreq_register(info);
    964         if (ret < 0) {
    965                 dev_err(&pdev->dev, "Failed to register cpufreq\n");
    966                 goto free_video_memory;
    967         }
    968
    969         ret = register_framebuffer(fbinfo);


    970         if (ret < 0) {
    971                 printk(KERN_ERR "Failed to register framebuffer device: %d\n",
    972                         ret);
    973                 goto free_cpufreq;
    974         }
    975
    976         /* create device files */
    977         ret = device_create_file(&pdev->dev, &dev_attr_debug);
    978         if (ret) {
    979                 printk(KERN_ERR "failed to add debug attribute\n");
    980         }
    981
    982         printk(KERN_INFO "fb%d: %s frame buffer device\n",
    983                 fbinfo->node, fbinfo->fix.id);
    984
    985         return 0;
    986
    987  free_cpufreq:
    988         s3c2410fb_cpufreq_deregister(info);
    989 free_video_memory:
    990         s3c2410fb_unmap_video_memory(fbinfo);
    991 release_clock:
    992         clk_disable(info->clk);


    993         clk_put(info->clk);
    994 release_irq:
    995         free_irq(irq, info);
    996 release_regs:
    997         iounmap(info->io);
    998 release_mem:
    999         release_resource(info->mem);
   1000         kfree(info->mem);
   1001 dealloc_fb:
   1002         platform_set_drvdata(pdev, NULL);
   1003         framebuffer_release(fbinfo);
   1004         return ret;
   1005 }
   1006
   1007 static int __init s3c2410fb_probe(struct platform_device *pdev)
   1008 {
   1009         return s3c24xxfb_probe(pdev, DRV_S3C2410);
   1010 }

相关推荐