zoukankan      html  css  js  c++  java
  • LCD驱动框架

    框架入口源文件: lcd.c 

    (可根据入口源文件,再按着框架到内核走一遍)

     内核版本:linux_2.6.22.6    硬件平台:JZ2440

     驱动框架:

    以下是驱动代码:

    LCD.c

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/errno.h>
    #include <linux/string.h>
    #include <linux/mm.h>
    #include <linux/slab.h>
    #include <linux/delay.h>
    #include <linux/fb.h>
    #include <linux/init.h>
    #include <linux/dma-mapping.h>
    #include <linux/interrupt.h>
    #include <linux/workqueue.h>
    #include <linux/wait.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <asm/div64.h>
    
    #include <asm/mach/map.h>
    #include <asm/arch/regs-lcd.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/arch/fb.h>
    
    
    //定义一个 fd_info 结构体
    static struct fb_info *s3c_lcd ;
    
    //IO寄存器
    static volatile unsigned long *gpccon;
    static volatile unsigned long *gpdcon;
    static volatile unsigned long *gpbdat;
    static volatile unsigned long *gpbcon;
    static volatile unsigned long *gpgcon;
    
    //LCD控制寄存器
    static struct lcd_con 
    {
         unsigned long LCDCON1; 
         unsigned long LCDCON2; 
         unsigned long LCDCON3; 
         unsigned long LCDCON4; 
         unsigned long LCDCON5; 
         unsigned long LCDSADDR1; 
         unsigned long LCDSADDR2; 
         unsigned long LCDSADDR3; 
         unsigned long REDLUT; 
         unsigned long GREENLUT; 
         unsigned long BLUELUT; 
         unsigned long RESERVE[9];   //guess why
         unsigned long DITHMODE; 
         unsigned long TPAL; 
         unsigned long LCDINTPND; 
         unsigned long LCDSRCPND; 
         unsigned long LCDINTMSK; 
         unsigned long LPCSEL; 
    };
    
    static volatile struct lcd_con *lcd_con;
    
    static int lcd_pseudo_palette(unsigned int regno,  unsigned int red,
                                   unsigned int green,  unsigned int blue,
                                   unsigned int transp, struct fb_info *info);
    
    
    //定义一个 fd_ops 结构体
    static struct fb_ops lcd_fb_fops =
    {
        .owner        = THIS_MODULE,
        .fb_setcolreg    = lcd_pseudo_palette,
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit    = cfb_imageblit,
    
    };
    
    //设置调色板
    static u32 pseudo_palette[16];
    
    static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
    {
        chan &= 0xffff;
        chan >>= 16 - bf->length;
        return chan << bf->offset;
    }
    
    
    static int lcd_pseudo_palette(unsigned int regno,  unsigned int red,
                                   unsigned int green,  unsigned int blue,
                                   unsigned int transp, struct fb_info *info)
    {
        unsigned int val;
        
        if (regno > 16)
            return 1;
    
        /* 用red,green,blue三原色构造出val */
        val  = chan_to_field(red,    &info->var.red);
        val |= chan_to_field(green, &info->var.green);
        val |= chan_to_field(blue,    &info->var.blue);
        
        //((u32 *)(info->pseudo_palette))[regno] = val;
        pseudo_palette[regno] = val;
        return 0;
    }
    
    static int lcd_init(void)
    {
    //申请一个     fd_info 结构体
       s3c_lcd = framebuffer_alloc(0,NULL);
    
    //初始化 fd_info 结构体
       /*设置固定参数*/
       strcpy(s3c_lcd->fix.id ," mylcd");
       s3c_lcd->fix.smem_len = 480*272*16/8;
       s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
       s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR;//lcd 类型
       s3c_lcd->fix.line_length = 480*2;
    
       /*设置可变参数*/
       s3c_lcd->var.xres =480;
       s3c_lcd->var.yres =272;
       s3c_lcd->var.xres_virtual =480;
       s3c_lcd->var.yres_virtual =272;
       s3c_lcd->var.bits_per_pixel =16;
       
       s3c_lcd->var.green.length =6;
       s3c_lcd->var.green.offset =5;
    
       s3c_lcd->var.red.length =5;
       s3c_lcd->var.red.offset =11;
    
       s3c_lcd->var.blue.length =5;
       s3c_lcd->var.blue.offset =0;
    
       s3c_lcd->var.activate = FB_ACTIVATE_NOW;
    
       /*设置操作函数*/
       s3c_lcd->fbops =&lcd_fb_fops;
    
       /*调色盘*/
       s3c_lcd->pseudo_palette = lcd_pseudo_palette;
       s3c_lcd->screen_size =480*272*2;
      
       //设置 LCD控制器寄存器          IO寄存器
       
         // 1.VD IO
         gpccon = ioremap(0x56000020,4); 
         gpdcon = ioremap(0x56000030,4);  
         *gpccon = 0xaaaaaaaa;
         *gpdcon = 0xaaaaaaaa;
         
         // 2. KEYBOARD LCD_PWENB
         gpbcon = ioremap(0x56000010,4);
         gpbdat = gpbcon +1;
         gpgcon = ioremap(0x56000060,4);
         *gpbcon &= ~3;   // gpb0 KEYBOARD 背光
         *gpbcon |= 1;
         *gpbdat &= ~1;
    
         *gpgcon |= (3<<8); //gpg4 LCD_PWENB 电源
         // 3. 控制寄存器
         lcd_con = ioremap(0x4d000000, sizeof(struct lcd_con));
         
             /* lcdcon1  
             * bit[17:8] VCLK = HCLK / [(CLKVAL + 1) × 2] VCLK=10000KHZ  HCLK=100000KHZ CLKVAL=4
             * bit[6:5]  0b11 tft_lcd 面板
             * bit[4:1]  0b1100 16bpp
             * bit[0]    0 禁止vd 1 使能vd
             */
             lcd_con->LCDCON1 = (4<<8)|(3<<5)|(12<<1)|(0<<0);
             
             /* lcdcon2  垂直方向时间参数
             * bit[31:24] VBPD 垂直同步周期后的的无效行数 lcd芯片手册p15                   T0-T2-T1= 327 - 322 - 1 = 4   3
             * bit[23:14] LINEVAL LCD 面板的垂直尺寸 320-1 = 319
             * bit[13:6]  VFPD 垂直同步周期前的的无效行数 t2 -t5 = 322 - 320 - 1 = 1   
             * bit[5:0]   VSPW  VSYNC 脉冲的高电平宽度 T1 -1 = 0
             */
             lcd_con->LCDCON2 =  (1<<24) | (271<<14) | (1<<6) | (9);
    
             /* lcdcon3  水平方向时间参数
             * bit[25:19]  tft_lcd  HSYNC 的下降沿与有效数据的开始之间的 VCLK 周期数  T6 -T7 -T8 = 17  16
             * bit[18:8]    LCD 面板的水平尺寸   240-1=239
             * bit[7:0]    有效数据的结束与 HSYNC 的上升沿之间的 VCLK 周期数 11 - 1 = 10
             */
             lcd_con->LCDCON3 =  (1<<19) | (479<<8) | (1);
    
             /* lcdcon4 水平方向同步信号
             * bit[15:8]  
             * bit[7:0]   算 VCLK 的数水平同步脉冲宽度决定 HSYNC 脉冲的高电平宽度  5-1=4
             */
             lcd_con->LCDCON4 = 40;
    
             /* lcdcon5
             * bit[11]  1  16bpp 5:6:5 格式
             * bit[10]  0 = VCLK 下降沿取视频数据
             * bit[9]   1 = HSYNC信号要反转,即低电平有效 
             * bit[8]   1 = VSYNC信号要反转,即低电平有效
             * bit[6]   0 = VDEN不用反转
             * bit[3]   0 = PWREN输出0
             
    * bit[1]  0 = BSWP
             * bit[0]   1 = HWSWP 2440手册P413
             */
             lcd_con->LCDCON5 = (1<<11)|(0<<10)|(1<<9)|(1<<8)|(0<<6)|(0<<3)|(0<<1)|(1<<0);
    
         // 4. 分配显存
         s3c_lcd->screen_base =dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,&s3c_lcd->fix.smem_start,GFP_KERNEL);
             
             
             /*
             * bit[29:21] 帧内存起始地址
             * bit[20:0]  视口缓冲区起始地址 
             */
             lcd_con->LCDSADDR1 = (s3c_lcd->fix.smem_start>>1)& ~(3<<30);
    
             /*
             * bit[20:0] 视口缓冲区结束地址 
             */
             lcd_con->LCDSADDR2 = ((s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len)>>1 ) & 0x1fffff;
    
             /*
             *  bit[21:11] 一行最后一个数据与下一行最开始数据的 差值的一半
             *  bit[10:0]  视口的宽度
             */
             lcd_con->LCDSADDR3 =480*1;
             
    //启动LCD
       lcd_con->LCDCON1 |= (1<<0);  /* 使能LCD控制器 */
       lcd_con->LCDCON5 |= (1<<3);  /* 使能LCD本身 */
       *gpbdat |= 1;                /* 输出高电平, 使能背光 */        
    
    
    //注册 fd_info 结构体
      register_framebuffer(s3c_lcd);
    
        return 0;
    }
    
    static void lcd_exit(void)
    {
       //去掉注册的 fd_info 结构体
       unregister_framebuffer(s3c_lcd);
    
       //释放 fd_info 结构体空间
       framebuffer_release(s3c_lcd);
    
       //取消映射
       iounmap(lcd_con);
       iounmap(gpbcon);
       iounmap(gpccon);
       iounmap(gpdcon);   
       iounmap(gpgcon); 
       iounmap(gpbdat);
    
       //释放帧内存
       dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
    
       //关闭LCD
       lcd_con->LCDCON1 &= ~(1<<0); /* 关闭LCD本身 */
       *gpbdat &= ~1;     /* 关闭背光 */
       
    }
    
    module_init(lcd_init);
    module_exit(lcd_exit);
    MODULE_LICENSE("GPL");

    以下是编译驱动的Makefile:

    KERN_DIR = /work/systems/kernel/linux-2/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += lcd.o
  • 相关阅读:
    番剧下载器
    ☕️【系统设计】如何设计出优雅且实用的 API 接口
    对象在内存中的内存布局是什么样的?
    稍等,我手机帮你远程调试下代码!
    Redis持久化整理
    git fork模式整理
    Java Lambda 表达式源码分析
    Java Stream 源码分析
    JVM G1GC的算法与实现
    域控批量创建域用户,并授权组
  • 原文地址:https://www.cnblogs.com/zsy12138/p/10391924.html
Copyright © 2011-2022 走看看