zoukankan      html  css  js  c++  java
  • 嵌入式Linux驱动学习之路(十八)LCD驱动

    驱动代码:

    /*************************************************************************
        > File Name: lcd.c
        > Author: 
        > Mail: 
        > Created Time: 2016年11月02日 星期三 15时21分59秒
     ************************************************************************/
    #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>
    
    static volatile unsigned long *gpbcon;
    static volatile unsigned long *gpbdat;
    
    static volatile unsigned long *gpccon;
    static volatile unsigned long *gpdcon;
    static volatile unsigned long *gpgcon;
    
    struct lcd_regs {
        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 reserved[9];
        unsigned long dithmode;
        unsigned long tpal;
        unsigned long lcdintpnd;
        unsigned long lcdsrcpnd;
        unsigned long lcdintmsk;
        unsigned long lpcsel;
    };
    
    static int s3c_lcdfb_setcolreg( unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info );
    static u32 pseudo_palette[16];
    static volatile struct lcd_regs *lcd_reg;  
    
    static struct fb_info *s3c_fb;
    
    static struct fb_ops s3c_fb_ops = {
            .owner= THIS_MODULE,
            .fb_setcolreg= s3c_lcdfb_setcolreg,
            .fb_fillrect= cfb_fillrect,   /* Needed !!! */
            .fb_copyarea= cfb_copyarea,/* Needed !!! */
            .fb_imageblit= cfb_imageblit,/* Needed !!! */
    };
    
    static unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
    {
        chan &= 0xffff;
        chan >>= 16 - bf->length;
        return chan << bf->offset;
    }
    
    /*调色板*/
    static int s3c_lcdfb_setcolreg( 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;
        /* 用红绿蓝构造出调色板 */
        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;
        return 0;
    }
    
    
    static int lcd_init( void )
    {
        /* 分配一个fb_info结构体 */
        s3c_fb = framebuffer_alloc(0,NULL);  //分配的空间为fb_info + 0 (0为私有空间)
    
        /* 设置 */
        /* 设置固定的参数 */
        strcpy( s3c_fb->fix.id, "mylcd" );
        s3c_fb->fix.smem_len = 240*320*16/8;
        s3c_fb->fix.type = FB_TYPE_PACKED_PIXELS;
        s3c_fb->fix.visual = FB_VISUAL_TRUECOLOR;   /* TFT*/
        s3c_fb->fix.line_length = 240*2;
    
        /* 设置可变的参数 */
        s3c_fb->var.xres = 240;
        s3c_fb->var.yres = 320;
        s3c_fb->var.xres_virtual = 240;
        s3c_fb->var.yres_virtual = 320;
        s3c_fb->var.xres_virtual = 240;
        s3c_fb->var.yres_virtual = 320;
        s3c_fb->var.bits_per_pixel = 16;
        
        s3c_fb->var.red.offset = 11;
        s3c_fb->var.red.length = 5;
    
        s3c_fb->var.green.offset = 5;
        s3c_fb->var.green.length = 6;
    
        s3c_fb->var.blue.offset = 0;
        s3c_fb->var.blue.length = 5;
    
        s3c_fb->var.activate = FB_ACTIVATE_NOW;
        
        /* 设置操作函数 */
        s3c_fb->fbops = &s3c_fb_ops;
    
    
        /* 其他设置 */
        s3c_fb->pseudo_palette = pseudo_palette;
        //s3c_fb->screen_base = ;           //显存的虚拟地址
        s3c_fb->screen_size = 240*324*2;    //显存的大小
        
        /* 配置GPIO */
        gpbcon = ioremap(0x56000010,8);
        gpbdat = gpbcon + 1;
        gpccon = ioremap(0x56000020,4);
        gpdcon = ioremap(0x56000030,4);
        gpgcon = ioremap(0x56000060,4);
    
        *gpccon = 0xaaaaaaaa; 
        *gpdcon = 0xaaaaaaaa;
        *gpbcon &= ~(3);
        *gpbcon |= 1;
        *gpbdat &= ~1; //关闭背光
        *gpgcon |= (3<<8); 
    
        /* 根据lcd手册 配置lcd控制器 */
        lcd_reg = ioremap(0x4d000000, sizeof(struct lcd_regs));
        /*
         * VCLK = HCLK / ((CLKVAL+1)*2)
         *
         * */
        lcd_reg->lcdcon1 = (4<<8)|(3<<5)|(0x0c<<1);
        /*
         * 垂直方向的时间参数
        * VBPD      是VSYNC之后再过多长时间才能发出第一行数据
        * LINEVAL   多少行数据 320
        * VFPD      发出最后一行数据之后过多久才发出VSYNC信号
        * VSPW      VSYNC信号的脉冲宽度
        * */
        lcd_reg->lcdcon2 = (3<<24)|(319<<14)|(1<<6)|(0);
    
        /*
        *  水平方向的时间参数
        *  HBPD     是HSYNC之后再过多长时间才能发出第一个像素数据
        *  HOZVAL   有多少列
        *  HFPD     发出一行的最后一个数据后再过多长时间发出HSYNC信号
        *  HSPW     HSYNC信号的脉冲宽度
        * */
        lcd_reg->lcdcon3 = (16<<19) | (239<<8) | (10<<0);
        lcd_reg->lcdcon4 = 4;
        
        /*
        * 信号的极性
        * bits[11] format for 565
        * bits[10] 上升沿有效 
        * bits[9]  HSYNC信号反转 
        * bits[8]  VSYNC信号反转
        * bits[7]  数据
        * bits[6]  VDEN
        * bits[3]  PWREN 
        * */
        lcd_reg->lcdcon5 = (1<<11) | (1<<9) | (1<<8) | (1<<0);
    
        /* 分配显存 */
        s3c_fb->screen_base = dma_alloc_writecombine(NULL, s3c_fb->fix.smem_len, &s3c_fb->fix.smem_start,GFP_KERNEL );
        lcd_reg->lcdsaddr1 = (s3c_fb->fix.smem_start >> 1) & ~(3<<30);
        lcd_reg->lcdsaddr2 = ((s3c_fb->fix.smem_start + s3c_fb->fix.smem_len)>>1) & 0x1fffff;
        lcd_reg->lcdsaddr3 = (240*16/16); /* 1行的长度  单位是2字节*/
    
        /**/
        lcd_reg->lcdcon1 |= 1;      /*使能LCD控制器*/
        lcd_reg->lcdcon5 |= (1<<3);   /* 使能LCD */
        *gpbdat |= 1;               /*使能背光*/
        /* 注册 */
        register_framebuffer(s3c_fb);
    
        return 0;
    }
    
    static void lcd_exit( void )
    {
        unregister_framebuffer(s3c_fb);
        lcd_reg->lcdcon1 &= ~1;
        *gpbdat &= ~1;
        dma_free_writecombine(NULL,s3c_fb->fix.smem_len,s3c_fb->screen_base,s3c_fb->fix.smem_start);
        iounmap(lcd_reg);
        iounmap(gpbcon);
        iounmap(gpccon);
        iounmap(gpdcon);
        iounmap(gpgcon);
        framebuffer_release(s3c_fb);
    }
    
    module_init(lcd_init);
    module_exit(lcd_exit);
    MODULE_LICENSE("GPL");

    注:这是240*320寸的屏幕。

    需要在配置内核的时候不要把lcd驱动编译到内核中。

    在安装驱动时会提示某些函数找不到。需要安装cfg*.ko等驱动模块。

    也可以将触摸屏和按键做为控制终端。需要在 /etc/inittab中添加

    tty1::askfirst:-/bin/sh
    即可!

    sd

  • 相关阅读:
    CF1539 VP 记录
    CF1529 VP 记录
    CF875C National Property 题解
    CF1545 比赛记录
    CF 1550 比赛记录
    CF1539E Game with Cards 题解
    CF1202F You Are Given Some Letters... 题解
    vmware Linux虚拟机挂载共享文件夹
    利用SOLR搭建企业搜索平台 之九(solr的查询语法)
    利用SOLR搭建企业搜索平台 之四(MultiCore)
  • 原文地址:https://www.cnblogs.com/ynxf/p/6028180.html
Copyright © 2011-2022 走看看