驱动代码:
/************************************************************************* > 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