⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cm240128-7.c

📁 用于接上8255的lcd的嵌入式linux下驱动程序以及相应的测试程序
💻 C
字号:
/*****************************************************************************
;www.hyesco.com
;Description: 	8255 driver on Linux for WANSHENG LCD(240*128)
;Date:		2007-6-6		
;Author:		
;E_mail:	luxg@hyesco.com
;					chenggp@hyesco.com
*****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/delay.h>

#include <asm/bitops.h>
#include <asm/arch/AT91RM9200_SYS.h>
#include <linux/devfs_fs_kernel.h>
#include "cm240128-7.h"


//82C55 addr struct defination	 
typedef struct _8255_ADDR 
{
	unsigned char	PA_8255_ADDR;	//0x00
	unsigned char	Reserved1;
	unsigned char	PB_8255_ADDR;	//0x02
	unsigned char	Reserved2;
	unsigned char	PC_8255_ADDR;	//0x04
	unsigned char	Reserved3;
	unsigned char	CW_8255_ADDR;	//0x06
	unsigned char	Reserved4;
}d8255_ADDR, *p8255_ADDR;    


//系统外设基地址:
//0x8000,0000: NCS7;
#define EBI_BASE_ADDRESS	0x80000000L
#define EBI_OFFSET_ADDRESS	0x0		     //82C55的偏移地址;
#define ADDR_sys_offset		EBI_BASE_ADDRESS + EBI_OFFSET_ADDRESS
#define ADDR_Size		0x20		   				//申请的地址空间大小

#define WriteDelay    20

static devfs_handle_t devfs_handle;			//设备文件的句柄
static char lcd_name[]="8255_lcddrv";		//设备的模块名
static unsigned int major =0;						//设备的主设备号(动态配置)
struct _8255_ADDR	*IO_Addr;		          //地址指针

//*********************************************************
//函数定义;
//*********************************************************
static int lcd_release(struct inode * inode,struct file * filp);
static int lcd_open(struct inode *,struct file *);
static int lcd_write(struct file *filp, const char *buf, size_t count,loff_t *f_pos);
static int lcd_ioctl(struct inode *,struct file *, unsigned int, unsigned long);

//*********************************************************
//文件操作结构体;
//*********************************************************
struct file_operations lcd_fops = {
 	owner:		        THIS_MODULE,
	release:        	lcd_release,
  open:           	lcd_open,	
  write:            lcd_write,
  ioctl:            lcd_ioctl,
};

//*********************************************************
//地址空间申请与检测函数;
//*********************************************************
static int ADDR_mem()
{
		
    //申请内存区域,以检测该地址空间是否被使用;
    if (!request_mem_region(ADDR_sys_offset,ADDR_Size,"IO_ADDR"))
		printk("Error request mem I/O address! \r\n"); 
    		
    //进行内存区域的映射,把物理地址映射为逻辑地址;  
    IO_Addr = (p8255_ADDR)ioremap_nocache(ADDR_sys_offset,ADDR_Size); 
		return 0;	
};


//**********************************************************
// 大延迟程序(毫秒级)
//**********************************************************
void delay_m(unsigned int time)
{
        unsigned int i;
        while(time--){
                i=1000;
                while(--i);
        }
}


//**********************************************************
// 延迟程序
//**********************************************************
void lcd_delay(unsigned char time1,unsigned char time2)
{
        unsigned char  z;
        z=time2;
        do
          {
           z=time2;
           do{ ;}while(z--);
          }while(time1--);
}


//*********************************************************
//写命令到LCD :
//*********************************************************
void lcd_wc(unsigned char lcd_code)/*写命令*/
{   
		IO_Addr -> PA_8255_ADDR &= ~LCD_PORT;				//数据线清零
		IO_Addr -> PA_8255_ADDR |= lcd_code;		    //写数据  
		IO_Addr -> PC_8255_ADDR &= ~LCD_CS1;				//使能LCD
		IO_Addr -> PC_8255_ADDR &= ~LCD_RS;					//RS=0  选择写缓存器
		lcd_delay(2,2); 
		IO_Addr -> PC_8255_ADDR |= LCD_RD;					//RD=1  
		IO_Addr -> PC_8255_ADDR &= ~LCD_WR;					//WR=0  
		lcd_delay(WriteDelay,WriteDelay); 
		IO_Addr -> PC_8255_ADDR |= LCD_WR;					//WR=1
		lcd_delay(2,2); 
		IO_Addr -> PC_8255_ADDR |= LCD_CS1; 				//CS1=1 禁能LCD
		lcd_delay(WriteDelay,WriteDelay);           //延迟,代替等待LCD不忙
}

//*********************************************************
// 写数据到 LCD :
//*********************************************************
void lcd_wd(unsigned char lcd_data)/*写数据*/
{
		IO_Addr -> PA_8255_ADDR &= ~LCD_PORT;					//数据线清零
		IO_Addr -> PA_8255_ADDR |= lcd_data;					//发送数据到数据线
		IO_Addr -> PC_8255_ADDR &= ~LCD_CS1;					//使能LCD
		IO_Addr -> PC_8255_ADDR |= LCD_RS;						//RS=1  
		IO_Addr -> PC_8255_ADDR |=LCD_RD;							//RD=1
		lcd_delay(2,2); 
		IO_Addr -> PC_8255_ADDR &= ~LCD_WR; 					//WR=0
		lcd_delay(WriteDelay,WriteDelay);        
		IO_Addr -> PC_8255_ADDR |= LCD_WR;  					//WR=1 
		lcd_delay(2,2);                
		IO_Addr -> PC_8255_ADDR &= ~LCD_RS;						//RS=0
		IO_Addr -> PC_8255_ADDR |= LCD_CS1;						//禁能LCD
		lcd_delay(WriteDelay,WriteDelay);  
}

//*********************************************************
// 写命令(先写寄存器地址后写数据)
//*********************************************************
void LCD_CmdWrite(unsigned char lcd_code,unsigned char lcd_data)
{
	lcd_wc(lcd_code);        //写命令
	lcd_delay(20,20);
	lcd_wc(lcd_data);        //写参数
	lcd_delay(20,20);
}

//*********************************************************
// 清屏:
//*********************************************************
void lcd_clear(void)
{
	LCD_CmdWrite(0x60,0x0);			//设置X坐标
	LCD_CmdWrite(0x70,0x0);			//设置Y坐标
	LCD_CmdWrite(0xE0,0x00);		//写入需要填充的数据 0x00
	LCD_CmdWrite(0xF0,0xa8);		//使F0的BIT[3]=1  开始填充  
	delay_m(1000);             
}

//*********************************************************
// LCD 初始化函数 :
//*********************************************************
void lcd_init(void)
{
	AT91_SYS->EBI_SMC2_CSR[7]= 0x11003183;
  IO_Addr -> CW_8255_ADDR  = 0x80; 
	IO_Addr -> PC_8255_ADDR |=LCD_RES;    
  IO_Addr -> PC_8255_ADDR &=~LCD_RES;			//复位										
  delay_m(1000);													//至少延迟250ms
  IO_Addr -> PC_8255_ADDR |=LCD_RES;
  IO_Addr -> PC_8255_ADDR |=LCD_RES;    
  IO_Addr -> PC_8255_ADDR &=~LCD_RES;			//复位										
  delay_m(1000);													//至少延迟250ms
  IO_Addr -> PC_8255_ADDR |=LCD_RES;
  IO_Addr -> PC_8255_ADDR |=LCD_CS1|LCD_RS|LCD_RD|LCD_WR;
  delay_m(1000);													//至少延迟50ms

	LCD_CmdWrite(0x00,0xC1);	//	图形模式,不开显示
	LCD_CmdWrite(0x02,0x10);	// 
	LCD_CmdWrite(0x03,0x80);	// 
	LCD_CmdWrite(0x10,0x6b);	// 不开光标  0x6f--开光标
	LCD_CmdWrite(0x11,0x00);	// 设定光标高度与行距
	LCD_CmdWrite(0x12,0x91);	// LCD 显示图层设定
	
	LCD_CmdWrite(0x20,0x1D);	// 工作窗口右边位置 1D=(240/8)-1=29
	LCD_CmdWrite(0x30,0x7F);	// 工作窗口底边位置 7F=128-1
	LCD_CmdWrite(0x40,0x00);	// 工作窗口左边位置
	LCD_CmdWrite(0x50,0x00);	// 工作窗口左边位置
	
	LCD_CmdWrite(0x21,0x1D);	// 显示窗口右边位置 1D=(240/8)-1=29
	LCD_CmdWrite(0x31,0x7F);	// 显示窗口底边位置 80=128
	LCD_CmdWrite(0x41,0x00);	// 显示窗口左边位置
	LCD_CmdWrite(0x51,0x00);	// 显示窗口左边位置
	
	LCD_CmdWrite(0xD0,0x80);	// 设定DAC 电流输出,可调整LCD 亮度
	
	LCD_CmdWrite(0xE0,0x00);	// 设定写入显示内存的数据(需搭配缓存器[F0]
	LCD_CmdWrite(0xF0,0xa0);	// 设定中文字型为”GB2323”
	LCD_CmdWrite(0xF1,0x0F);	// 改变字型垂直与水平显示大小

	LCD_CmdWrite(0x01,0xF0);	// 系统工作频率与中断准位设定
	LCD_CmdWrite(0x81,0x04);	// 变换FRM 极性的起始地址(Common)
	LCD_CmdWrite(0x91,0x00);	// 变换FRM 极性的结束地址(Common)
	LCD_CmdWrite(0x90,0x0f);	// 刷新频率	
	
	LCD_CmdWrite(0x60,0x0);		//清屏
	LCD_CmdWrite(0x70,0x0);			
	LCD_CmdWrite(0xE0,0x00);		
	LCD_CmdWrite(0xF0,0xa8);		
	delay_m(500);
	
	LCD_CmdWrite(0x00,0xcd);	
	LCD_CmdWrite(0x60,0x00);
	LCD_CmdWrite(0x70,0x00);
	lcd_wd(0xd7);									//"注"
	lcd_wd(0xa2);
		
	LCD_CmdWrite(0x60,0x02);
	LCD_CmdWrite(0x70,0x00);
	lcd_wd(0xb2);									//"测"
	lcd_wd(0xe2);
	
	LCD_CmdWrite(0x60,0x04);
	LCD_CmdWrite(0x70,0x00);
	lcd_wd(0xb3);									//"成"
	lcd_wd(0xc9);
		
	LCD_CmdWrite(0x60,0x06);
	LCD_CmdWrite(0x70,0x00);
	lcd_wd(0xb9);									//"功"
	lcd_wd(0xa6);
	
	
}

//*********************************************************
//  LCD open 函数:
//*********************************************************
int lcd_open(struct inode * inode, struct file * filp)
{

  IO_Addr -> PC_8255_ADDR |= LCD_RES;
  IO_Addr -> PC_8255_ADDR |= LCD_BACKLIGHT;
	MOD_INC_USE_COUNT;
	return 0;
}

//*********************************************************
//LCD release 函数 :
//*********************************************************
int lcd_release(struct inode * inode,struct file * filp)
{
	MOD_DEC_USE_COUNT;
	return 0;
}	

//*********************************************************
// LCD ioctl 函数:
//*********************************************************
int lcd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
	 switch (cmd) 
	    {	
	      case DISPLAY_T_ON:       //开文本显示    
	    		{
	    			 LCD_CmdWrite(0x00,0xcd); 
	    		 	 break; 
	      	}
	      case DISPLAY_G_ON:			//开图形显示  
	    		{
	    			 LCD_CmdWrite(0x00,0xc5); 
	    		 	 break; 
	      	}
	      case BACKLIGHT_ON:			//开背光
	    		{
	    			 IO_Addr -> PC_8255_ADDR |=LCD_BACKLIGHT;		
	    		 	 break; 
	      	}
	      case BACKLIGHT_OFF:			//关背光
	    		{
	    			IO_Addr -> PC_8255_ADDR &=~LCD_BACKLIGHT;		
	    		 	 break; 
	      	}
	      case SET_X:							//设置X坐标
	    		{
	    			 LCD_CmdWrite(0x60,(unsigned char)arg); 
	    		 	 break; 
	      	}
	       case SET_Y:						//设置Y坐标
	    		{
	    			 LCD_CmdWrite(0x70,(unsigned char)arg);
	    		 	 break; 
	      	}
	      	case CLR:							//清屏
	      		{ 
	      		  lcd_clear();   
	      		  break;
	      		}
	      	case FONT:
	      		{
	      			LCD_CmdWrite(0xf1,(unsigned char)arg);
	      			break;	
	      		}
	     
	       default:
	       	break;
	    }
	
	return 0;	  	       	            
}

//*********************************************************
// 写数据到LCD:
//*********************************************************
int lcd_write(struct file *filp, const char *buf, size_t count,loff_t *f_pos)
{  
		unsigned int len,i;
	  unsigned char tempbuf[128*30];
	  
	  len=count;
	  if(len > 128*30)
	  	return -1;
	  	
		//拷贝用户数据到内核
		copy_from_user(tempbuf, buf, len);
             
		for(i=0;i<len;i++)
	      {
	      	 //写字符数据到DDRAM
	      	 lcd_wd(tempbuf[i]);
	      	 udelay(15);
	      } 
	 	return 0 ;		
}

//*********************************************************
// 注册模块:
//*********************************************************
int __init LCD_at91_init(void)
{	
	   unsigned int result = 0;
      
     // 注册设备驱动模块	  
	   if((result= devfs_register_chrdev(major, lcd_name, &lcd_fops)) < 0) 
	      {
		      printk("<1>devfs_register_chrdev err!\n");
		      return result;
	      }

     if(major==0)
        major=result;
			
		 ADDR_mem();  //地址空间申请
      printk("init IO_ADDR module is ok!\n");
      
     // 建立设备文件节点     
      devfs_handle = devfs_register(NULL, "8255_lcd7",DEVFS_FL_DEFAULT,
                        major, 0, S_IFCHR | S_IRUSR | S_IWUSR,&lcd_fops, NULL);
                        
	   lcd_init();     // 初始化LCD
	   IO_Addr -> PC_8255_ADDR |=LCD_BACKLIGHT;          //开背光
     return 0;
}

//*********************************************************
// 注销模块:
//*********************************************************
void __exit LCD_at91_cleanup(void)
{
	int retv;
    
  AT91_SYS->PIOB_CODR |=LCD_BACKLIGHT;				//开背光
  LCD_CmdWrite(0x00,0xC1); 										//关显示
  if((retv=devfs_unregister_chrdev(major,lcd_name))<0)
      {
        printk("<1>UnRegister Fail!\n");
        return;
      }
}


module_init(LCD_at91_init);
module_exit(LCD_at91_cleanup);

MODULE_AUTHOR("<luxg@hyesco.com>");
MODULE_DESCRIPTION("AT91 LCD Driver (AT91_LCD)");
MODULE_LICENSE("GPL");
	  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -