📄 cm240128-7.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 + -