该驱动LCD了,还是走我的不寻常路,官方使用的时framebuffer的方式实现的LCD驱动。我还是老样子使用混杂设备,难点在以下几点:
1.申请连续的物理内存空间
2.分辨好给LCD帧缓冲器是物理地址而不是虚拟地址,申请完物理空间后得到的时虚拟地址,得调用函数将虚拟地址转换为物理地址,然后再赋值给LCD的三个寄存器。
在这里我所需要设置的LCD控制器寄存器都是使用IOREMAP映射过来的,直接对寄存器进行操作,目前我经过更换显存空间的数据可以看到LCD显示不同的颜色,其他的我没太深究,毕竟只是学习学习,驱动里面有不少漏洞我懒的改了,朋友们如果想把这个程序用于自己的产品的话,建议将程序从头看看,填补漏洞呵呵。
下面列出驱动程序。填充缓冲器颜色的程序我再OPEN函数里写的,所以应用程序只需要打开设备文件屏幕就可以自动显示出相应的颜色了
一。驱动程序:
/*********************************
** LCD 驱动程序 **
*********************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "tft_tb35_micro2440_drv"
//寄存器定义
static void __iomem *base_addr;
static void __iomem *base_addr1;
static void __iomem *base_addr2;
static void __iomem *base_addr3;
static void __iomem *base_addr4;
#define LCDCON1_MICRO2440 (*(volatile unsigned long *)(base_addr + 0)) //LCD控制1寄存器
#define LCDCON2_MICRO2440 (*(volatile unsigned long *)(base_addr+4)) //LCD控制2寄存器
#define LCDCON3_MICRO2440 (*(volatile unsigned long *)(base_addr+8)) //LCD控制3寄存器
#define LCDCON4_MICRO2440 (*(volatile unsigned long *)(base_addr+0x0c))//LCD控制4寄存器
#define LCDCON5_MICRO2440 (*(volatile unsigned long *)(base_addr+0x10))//LCD控制5寄存器
#define LCDSADDR1_MICRO2440 (*(volatile unsigned long *)(base_addr+0x14))//帧缓冲器开始地址1寄存器
#define LCDSADDR2_MICRO2440 (*(volatile unsigned long *)(base_addr+0x18))//帧缓冲器开始地址2寄存器
#define LCDSADDR3_MICRO2440 (*(volatile unsigned long *)(base_addr+0x1c))//帧缓冲器开始地址3寄存器
#define REDLUT_MICRO2440 (*(volatile unsigned long *)(base_addr+0x20))//红色查找表寄存器
#define GREENLUT_MICRO2440 (*(volatile unsigned long *)(base_addr+0x24))//绿色查找表寄存器
#define BLUELUT_MICRO2440 (*(volatile unsigned long *)(base_addr+0x28))//蓝色查找表寄存器
#define DITHMODE_MICRO2440 (*(volatile unsigned long *)(base_addr1+0)) //抖动模式寄存器
#define TPAL_MICRO2440 (*(volatile unsigned long *)(base_addr1+0x04))//临时调色板寄存器
#define LCDINTPND_MICRO2440 (*(volatile unsigned long *)(base_addr1+0x08))//LCD中断挂起寄存器
#define LCDSRCPND_MICRO2440 (*(volatile unsigned long *)(base_addr1+0x0c))//LCD源挂起寄存器
#define LCDINTMSK_MICRO2440 (*(volatile unsigned long *)(base_addr1+0x10))//LCD中断屏蔽寄存器
#define TCONSEL_MICRO2440 (*(volatile unsigned long *)(base_addr1+0x14))//TCON控制寄存器
#define GPCCON_MICRO2440 (*(volatile unsigned long *)(base_addr2+0))
#define GPCDAT_MICRO2440 (*(volatile unsigned long *)(base_addr2+0x04))
#define GPCUP_MICRO2440 (*(volatile unsigned long *)(base_addr2+0x08))
#define GPDCON_MICRO2440 (*(volatile unsigned long *)(base_addr2+0x10))
#define GPDDAT_MICRO2440 (*(volatile unsigned long *)(base_addr2+0x14))
#define GPDUP_MICRO2440 (*(volatile unsigned long *)(base_addr2+0x18))
#define GPGCON_MICRO2440 (*(volatile unsigned long *)(base_addr3+0))
#define GPGDAT_MICRO2440 (*(volatile unsigned long *)(base_addr3+4))
#define GPGUP_MICRO2440 (*(volatile unsigned long *)(base_addr3+8))
#define LCD_BUFFER_ADDRESS (*(volatile unsigned long *)(base_addr4+0))
#define LOWER21BITS(n) ((n)&0x1fffff)
#define BPPMODE_1BPP 0x08
#define BPPMODE_2BPP 0x09
#define BPPMODE_4BPP 0x0a
#define BPPMODE_8BPP 0x0b
#define BPPMODE_16BPP 0x0c
#define BPPMODE_24BPP 0x0d
#define LCDTYPE_TFT 0x03
#define ENVID_DISABLE 0
#define ENVID_ENABLE 1
#define FORMAT8BPP_5551 0
#define FORMAT8BPP_565 1
#define HSYNC_NORM 0
#define HSYNC_INV 1
#define VSYNC_NORM 0
#define VSYNC_INV 1
#define BSWP 1
#define HWSWP 1
//TFT LCD PANEL(240*320)
#define MODE_TFT_1BIT_240320 (0x4101)
#define MODE_TFT_8BIT_240320 (0x4102)
#define MODE_TFT_16BIT_240320 (0x4104)
#define MODE_TFT_24BIT_240320 (0x4108)
//TFT240320
#define LCD_XSIZE_TFT_240320 (240)
#define LCD_YSIZE_TFT_240320 (320)
#define HOZVAL_TFT_240320 (LCD_XSIZE_TFT_240320-1)
#define LINEVAL_TFT_240320 (LCD_YSIZE_TFT_240320-1)
#define CLKVAL_TFT_240320 (7)
#define VBPD_240320 1
#define VFPD_240320 2
#define VSPW_240320 1
#define HBPD_240320 19
#define HFPD_240320 10
#define HSPW_240320 10
#define LCDFRAMEBUFFER 0x30400000
unsigned long fb_base_addr;
unsigned int bpp;
unsigned int xsize;
unsigned int ysize;
unsigned long lcd_buffer_base_addr;
unsigned long phyaddr;
static struct semaphore lock;
static struct clk *tft_clock;
unsigned long hclk;
struct page *data_temp;
unsigned long address;
static void tft_tb35_init(void)
{
unsigned char red,green,blue;
unsigned short *addr;
unsigned int i,j;
//IO映射
base_addr=ioremap(0x4d000000,0x30);
base_addr1=ioremap(0x4d00004c,0x16);
base_addr2=ioremap(0x56000020,0x20);
base_addr3=ioremap(0x56000060,0x20);
//获取时钟
tft_clock = clk_get(NULL, "hclk");//获取PCLK
clk_enable(tft_clock);
hclk= clk_get_rate(tft_clock);
//设置IO口
GPCUP_MICRO2440=0xffffffff;
GPDUP_MICRO2440=0xffffffff;
GPCCON_MICRO2440=0xaaaaaaaa;
GPDCON_MICRO2440=0xaaaaaaaa;
GPGCON_MICRO2440=(GPGCON_MICRO2440&(~(3<<8)))|(3<<8);
GPGUP_MICRO2440=(GPGUP_MICRO2440&(~(1<<4)))|(1<<4);
//LCD初始化
LCDCON1_MICRO2440=(CLKVAL_TFT_240320<<8)|(LCDTYPE_TFT<<5)|(BPPMODE_16BPP<<1)|(ENVID_DISABLE<<0);
LCDCON2_MICRO2440=(VBPD_240320<<24)|(LINEVAL_TFT_240320<<14)|(VFPD_240320<<6)|(VSPW_240320);
LCDCON3_MICRO2440=(HBPD_240320<<19)|(HOZVAL_TFT_240320<<8)|(HFPD_240320);
LCDCON4_MICRO2440=HSPW_240320;
LCDCON5_MICRO2440=(FORMAT8BPP_565<<11)|(HSYNC_INV<<9)|(VSYNC_INV<<8)|(HWSWP<<1);
LCDCON5_MICRO2440=(LCDCON5_MICRO2440&(~(1<<5)))|(0<<5);
LCDCON5_MICRO2440=(LCDCON5_MICRO2440&(~(1<<3)))|(1<<3);
//申请连续物理地址
data_temp=alloc_pages(GFP_KERNEL,9);
lcd_buffer_base_addr=(unsigned long)page_address(data_temp);
//base_addr4=ioremap(lcd_buffer_base_addr,2097152);
//定义LCD显存
//address=(unsigned long)(&LCD_BUFFER_ADDRESS);
phyaddr=virt_to_phys(lcd_buffer_base_addr);
LCDSADDR1_MICRO2440=(((phyaddr)>>22)<<21)|LOWER21BITS((phyaddr)>>1);
LCDSADDR2_MICRO2440=LOWER21BITS((phyaddr+(LINEVAL_TFT_240320+1)*(HOZVAL_TFT_240320+1)*2)>>1);
LCDSADDR3_MICRO2440=(0<<11)|(LCD_XSIZE_TFT_240320*2/2);
TPAL_MICRO2440=0;
fb_base_addr=lcd_buffer_base_addr;
bpp=16;
xsize=240;
ysize=320;
LCDCON1_MICRO2440=LCDCON1_MICRO2440|(ENVID_ENABLE<<0);
addr=fb_base_addr;//+(10*xsize+100);
while(1)
{
if(addr==(fb_base_addr+150000))
addr=fb_base_addr;
else
addr++;
*addr=0x77;
LCDCON1_MICRO2440=LCDCON1_MICRO2440|(ENVID_ENABLE<<0);
LCDCON5_MICRO2440=(LCDCON5_MICRO2440&(~(1<<5)))|(0<<5);
LCDCON5_MICRO2440=(LCDCON5_MICRO2440&(~(1<<3)))|(1<<3);
}
//for(i=0;i // {
// for(j=0;j // {
// addr=fb_base_addr+i*xsize+j;
// *addr=0;
// }
// }
//
}
static ssize_t tft_write(struct file *file,char *buf,size_t count,loff_t *ppos)
{
unsigned long ret=0;
ret=(unsigned long)copy_from_user(address,buf,count);
//int i=0;
//int transferred=0;
//int ret,my_buf[512];
//struct at24lc04_dev *dev=(struct at24lc04_dev *)file->private_data;
// dev->current_pointer=*ppos;
// if(i2c_check_functionality(dev->client->adapter,I2C_FUNC_SMBUS_READ_BYTE_DATA))
// {copy_from_user(my_buf,buf,count);
// while(transferred // {
// ret=i2c_smbus_write_byte_data(dev->client,dev->current_pointer+i,my_buf[i]);
// i=i+1;
// transferred+=1;
// }
// dev->current_pointer+=transferred;
// }
return ret;
}
static int tft_open(struct inode *inode,struct file *file)
{
int ret;
ret=down_trylock(&lock);
if(ret==0)
{
tft_tb35_init();
return 0;
}
else
return -EBUSY;
}
static int tft_close(struct inode *inodep,struct file *file)
{
iounmap(base_addr);
iounmap(base_addr1);
iounmap(base_addr2);
iounmap(base_addr3);
iounmap(base_addr4);
clk_disable(tft_clock);
clk_put(tft_clock);
tft_clock=NULL;
up(&lock);//释放互斥锁
return 0;
}
static struct file_operations dev_fops={
.owner=THIS_MODULE,
.open=tft_open,
.release=tft_close,
//.read=tft_read,
.write=tft_write,
};
static struct miscdevice misc={
.name=DEVICE_NAME,
.minor=MISC_DYNAMIC_MINOR,
.fops=&dev_fops,
};
static int __init tft_micro2440_init(void)
{
int ret;
init_MUTEX(&lock);
ret=misc_register(&misc);
return ret;
}
void __exit tft_micro2440_exit(void)
{
misc_deregister(&misc);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xubin");
module_init(tft_micro2440_init);
module_exit(tft_micro2440_exit);
二。应用程序:
#include
#include
#include
#include
#include
#include
#define PWM_START 0x01
#define PWM_STOP 0x02
int main(int argc,char **argv)
{
unsigned long i=1;
int fd;
fd=open("/dev/tft_tb35_micro2440_drv",O_RDWR);
if(fd<0)
{
printf("error\n");
exit(1);
}
while(1)
{
sleep(60);
//ioctl(fd,PWM_STOP,NULL);
}
close(fd);
return 0;
}