• 嵌入式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

  • 相关阅读:
    洛谷P1613 跑路
    洛谷P2149 Elaxia的路线
    洛谷P3119 草鉴定
    洛谷P1972 HH的项链
    洛谷P2458 保安站岗
    uva10061
    uva579
    uva 127 "Accordian" Patience
    uva10177 (2/3/4)-D Sqr/Rects/Cubes/Boxes?
    uva156
  • 原文地址:https://www.cnblogs.com/ynxf/p/6028180.html
Copyright © 2020-2023  润新知