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 }