-
内容介绍:之前有一个项目想要使用Linux系统但是为了省电及节约成本就使用一个黑白液晶屏,现在把驱动调试设计过程记录一下.
Linux内核: linux-2.6.35.3
Board: ZLG iMX287开发板
液晶屏: ZLE12864A-FFSSWE-NAA是一个ZigBee开发板的液晶模块.
首先最主要的工作就是液晶驱动的设计,对于这种液晶,没办法使用iMX287芯片的LCD Interface,所以只能使用GPIO口来模拟时序了.如果写一个通用的字符设备驱动也可以,但是这毕竟不是很好的办法.所以还是要使用FrameBuffer的驱动.
首先找到我们的参考驱动drivers/auxdisplay
其说明文档在Documentation/auxdisplay/中
首先这个驱动是给x86电脑使用的,通过并口来连接.这里用我们的ARM操作就需要使用GPIO来操作.
修改之后的接口连接(使用串行接口模式)
CS -> P2.12
SCL -> P2.14
SI -> P2.15
RST -> P2.4
A0 -> P2.13
下面写出12864操作函数接口模块,这里实现了接口,模块很简单,没什么好说的.
-
/*
-
* 2015-01-21 20:53:59
-
* LCD接口函数实现
-
*
-
*
-
**/
-
#include<linux/module.h> /* module */
-
#include<linux/fs.h> /* file operation */
-
#include<asm/uaccess.h> /* get_user() */
-
#include<asm/io.h> /* ioctl */
-
#include "mach/regs-pinctrl.h"/*GPIO REG Address*/
-
#include "lcd12864.h"
-
typedef unsigned char uchar;
-
typedef unsigned char uint8;
-
typedef unsigned int uint16;
-
-
void __iomem *pinctrl_base = NULL;
-
-
#define L_CS(a) do{ writel(1<<12, pinctrl_base + HW_PINCTRL_DOUT2_CLR-(a<<2)); }while(0)
-
//CS P2.12
-
#define L_LD(a) do{ writel(1<<13, pinctrl_base + HW_PINCTRL_DOUT2_CLR-(a<<2)); }while(0)
-
//A0=H data A0=L command P2.13
-
#define L_CK(a) do{ writel(1<<14, pinctrl_base + HW_PINCTRL_DOUT2_CLR-(a<<2)); }while(0)
-
//CLK P2.14
-
#define L_DA(a) do{ writel(1<<15, pinctrl_base + HW_PINCTRL_DOUT2_CLR-(a<<2)); }while(0)
-
//SI P2.15
-
#define L_BK(a) do{;}while(0) //backlight
-
#define L_RST(a) do{ writel(1<<4, pinctrl_base + HW_PINCTRL_DOUT2_CLR-(a<<2)); }while(0)
-
//RST P2.4
-
-
-
void lcd12864_writecmd(unsigned char Command)
-
{
-
unsigned char j, bit7;
-
-
L_CK(1); // = 1;
-
L_LD(0); // = 0;
-
L_CS(0); // = 0;
-
for (j = 0; j < 8; j++)
-
{
-
bit7 = Command & 0x80;
-
if (bit7 == 0)
-
{
-
L_DA(0); // = 0;
-
}
-
else
-
{
-
L_DA(1); // = 1;
-
}
-
L_CK(0); // = 0;
-
// delay_us(10);
-
L_CK(1); // = 1;
-
Command = Command << 1;
-
}
-
L_CS(1); // = 1;
-
}
-
-
void lcd12864_writedata(unsigned char DDate)
-
{
-
unsigned char j, bit7;
-
L_CK(1); // = 1;
-
L_LD(1); // = 1;
-
L_CS(0); // = 0;
-
for (j = 0; j < 8; j++)
-
{
-
bit7 = DDate & 0x80;
-
if (bit7 == 0)
-
{
-
L_DA(0); // = 0;
-
}
-
else
-
{
-
L_DA(1); // = 1;
-
}
-
L_CK(0); // = 0;
-
// delay_us(10);
-
L_CK(1); // = 1;
-
DDate = DDate << 1;
-
}
-
L_CS(1); // = 1;
-
}
-
-
void initLCDM(void)
-
{
-
uchar ContrastLevel;//定义对比度
-
ContrastLevel = 0xa0;//对比度,根据不同的 LCD 调节,否则无法显示。
-
lcd12864_writecmd(0xaf);//开显示
-
lcd12864_writecmd(0x40);//显示起始行为 0
-
lcd12864_writecmd(0xa0);//RAM 列地址与列驱动同顺序
-
lcd12864_writecmd(0xa6);//正向显示
-
lcd12864_writecmd(0xa4);//显示全亮功能关闭
-
lcd12864_writecmd(0xa2);//LCD 偏压比 1/9
-
lcd12864_writecmd(0xc8);//行驱动方向为反向
-
lcd12864_writecmd(0x2f);//启用内部 LCD 驱动电源
-
lcd12864_writecmd(0xf8);//升压电路设置指令代码
-
lcd12864_writecmd(0x00);//倍压设置为 4X
-
lcd12864_writecmd(ContrastLevel); //设置对比度
-
lcd12864_writecmd(0xaf);//开显示
-
}
-
-
-
-
void ResetLCD(void)
-
{
-
L_RST(1);
-
L_RST(0);
-
// delay_ms(10);
-
L_RST(1);
-
-
-
}
-
-
void ClearRAM(void)
-
{
-
uint8 i,j;
-
for (i = 0; i < 8; i++)
-
{
-
lcd12864_writecmd(i|0xb0);
-
lcd12864_writecmd(0x10);
-
lcd12864_writecmd(0x00);
-
for (j = 0; j < 132; j++)
-
{
-
lcd12864_writedata(0xAA);
-
}
-
}
-
}
-
-
static unsigned int is_lcd12864_inited = 0;
-
-
unsigned int lcd12864_isinited(void){
-
return is_lcd12864_inited;
-
}
-
-
EXPORT_SYMBOL_GPL(lcd12864_writedata);
-
EXPORT_SYMBOL_GPL(lcd12864_writecmd);
-
EXPORT_SYMBOL_GPL(lcd12864_isinited);
-
-
-
/*********************************************************************************************************
-
Module Functions
-
*********************************************************************************************************/
-
static int __init lcdModule_init (void)
-
{
-
int iRet=0;
-
printk("\nlcd12864 module init!\n");
-
//printk("you should see a few line on LCDi\n");
-
pinctrl_base = ioremap(0x80018000, 0x1B80);
-
writel(0xFF<<24 | 0x300, pinctrl_base+HW_PINCTRL_MUXSEL4_SET);
-
//set io port mode for 2.12,2.13,2.14,2.15 to GPIO
-
writel(0xF<<12|0x1<<4, pinctrl_base+HW_PINCTRL_DOE2_SET); //set to output mode
-
ResetLCD();
-
initLCDM();
-
ClearRAM(); //请液晶缓存
-
//lcd12864_writecmd(0xA7);
-
is_lcd12864_inited = 1;
-
return iRet;
-
}
-
static void __exit lcdModule_exit (void) /* warning:return void */
-
{
-
printk("\nlcd module exit!\n");
-
iounmap(pinctrl_base);
-
is_lcd12864_inited = 0;
-
}
-
-
/*********************************************************************************************************
-
Driver Definitions
-
*********************************************************************************************************/
-
module_init(lcdModule_init);
-
module_exit(lcdModule_exit);
-
-
MODULE_LICENSE("Dual BSD/GPL");
-
MODULE_AUTHOR("schspa@gmail.com");
-
MODULE_DESCRIPTION("iMX287 lcd12864 driver By Schspa");
下面是重要的内容,我们的FrameBuffer接口
注意我们的在mmap函数中的vma->vm_pgoff之前老是映射的不对,加上之后就对了
-
/*
-
* Filename: cfag12864bfb.c
-
* Version: 0.1.0
-
* Description: cfag12864b LCD framebuffer driver
-
* License: GPLv2
-
* Depends: cfag12864b
-
*
-
* Author: Copyright (C) Miguel Ojeda Sandonis
-
* Date: 2006-10-31
-
*
-
* Modified: schspa
-
* Data: 2015-01-21
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License version 2 as
-
* published by the Free Software Foundation.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
*
-
*/
-
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/delay.h>
-
#include <linux/errno.h>
-
#include <linux/fb.h>
-
#include <linux/mm.h>
-
#include <linux/platform_device.h>
-
#include <linux/string.h>
-
#include <linux/uaccess.h>
-
#include <linux/cfag12864b.h>
-
#include <asm/cacheflush.h>
-
void cfag12864b_sync(void);
-
extern unsigned char *cfag12864b_buffer_nocache;
-
#define CFAG12864BFB_NAME "cfag12864bfb"
-
-
static struct fb_fix_screeninfo cfag12864bfb_fix __devinitdata = {
-
.id = "cfag12864b",
-
.type = FB_TYPE_PACKED_PIXELS,
-
.visual = FB_VISUAL_MONO10,
-
.xpanstep = 0,
-
.ypanstep = 0,
-
.ywrapstep = 0,
-
.line_length = CFAG12864B_WIDTH / 8,
-
.accel = FB_ACCEL_NONE,
-
};
-
-
static struct fb_var_screeninfo cfag12864bfb_var __devinitdata = {
-
.xres = CFAG12864B_WIDTH,
-
.yres = CFAG12864B_HEIGHT,
-
.xres_virtual = CFAG12864B_WIDTH,
-
.yres_virtual = CFAG12864B_HEIGHT,
-
.bits_per_pixel = 1,
-
.red = { 0, 1, 0 },
-
.green = { 0, 1, 0 },
-
.blue = { 0, 1, 0 },
-
.left_margin = 0,
-
.right_margin = 0,
-
.upper_margin = 0,
-
.lower_margin = 0,
-
.vmode = FB_VMODE_NONINTERLACED,
-
};
-
-
static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-
{
-
printk("cfag12864bfb_mmap\r\n");
-
unsigned long page;
-
unsigned char i;
-
unsigned long start = (unsigned long)vma->vm_start;
-
//unsigned long end = (unsigned long)vma->vm_end;
-
unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);
-
//if(size > CFAG12864B_SIZE){
-
printk("size %d \n", size);
-
// return -ENOMEM;
-
//}
-
vma->vm_flags |= VM_IO | VM_SHARED;
-
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
//得到物理地址 注意这里边的vma->vm_pgoff 负责可能出现不正常的情况.
-
page = virt_to_phys(cfag12864b_buffer+vma->vm_pgoff);
-
//将用户空间的一个vma虚拟内存区映射到以page开始的一段连续物理页面上
-
if(remap_pfn_range(vma,start,page>>PAGE_SHIFT,size,PAGE_SHARED)){//第三个参数是页帧号,由物理地址右移PAGE_SHIFT得到
-
printk("remap_pfn_range failed\r\n");
-
return -1;
-
}
-
return 0;
-
// return vm_insert_page(vma, vma->vm_start,
-
// virt_to_page(cfag12864b_buffer));
-
}
-
-
static int cfag12864bfb_sync(struct fb_info *info)
-
{
-
printk("fb_sync\r\n");
-
cfag12864b_sync();
-
return 0;//vm_insert_page(vma, vma->vm_start,
-
//virt_to_page(cfag12864b_buffer));
-
}
-
static int cfag12864bfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){
-
-
-
int i = 0;
-
printk("fb ioctl %d\r\n", cmd);
-
cfag12864b_sync();
-
return 0;
-
}
-
static struct fb_ops cfag12864bfb_ops = {
-
.owner = THIS_MODULE,
-
// .fb_read = fb_sys_read,
-
// .fb_write = fb_sys_write,
-
// .fb_fillrect = sys_fillrect,
-
// .fb_copyarea = sys_copyarea,
-
// .fb_imageblit = sys_imageblit,
-
.fb_ioctl = cfag12864bfb_ioctl,
-
.fb_mmap = cfag12864bfb_mmap,
-
.fb_sync = cfag12864bfb_sync,
-
};
-
-
static int __devinit cfag12864bfb_probe(struct platform_device *device)
-
{
-
int i = 0;
-
int ret = -EINVAL;
-
struct fb_info *info = framebuffer_alloc(0, &device->dev);
-
-
if (!info)
-
goto none;
-
-
info->screen_base = (char __iomem *) cfag12864b_buffer;
-
info->screen_size = CFAG12864B_SIZE;
-
info->fbops = &cfag12864bfb_ops;
-
info->fix = cfag12864bfb_fix;
-
info->var = cfag12864bfb_var;
-
info->pseudo_palette = NULL;
-
info->par = NULL;
-
info->flags = FBINFO_FLAG_DEFAULT;
-
-
if (register_framebuffer(info) < 0)
-
goto fballoced;
-
-
platform_set_drvdata(device, info);
-
-
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
-
info->fix.id);
-
for(i = 0; i<1024; i++){
-
info->screen_base[i] = 0x0F;
-
}
-
return 0;
-
-
fballoced:
-
framebuffer_release(info);
-
-
none:
-
return ret;
-
}
-
-
static int __devexit cfag12864bfb_remove(struct platform_device *device)
-
{
-
struct fb_info *info = platform_get_drvdata(device);
-
-
if (info) {
-
unregister_framebuffer(info);
-
framebuffer_release(info);
-
}
-
-
return 0;
-
}
-
-
static struct platform_driver cfag12864bfb_driver = {
-
.probe = cfag12864bfb_probe,
-
.remove = __devexit_p(cfag12864bfb_remove),
-
.driver = {
-
.name = CFAG12864BFB_NAME,
-
},
-
};
-
-
static struct platform_device *cfag12864bfb_device;
-
-
static int __init cfag12864bfb_init(void)
-
{
-
int ret = -EINVAL;
-
//printk("PAGE_SIZE:%d\r\n",PAGE_SIZE);
-
/* cfag12864b_init() must be called first */
-
if (!cfag12864b_isinited()) {
-
printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
-
"cfag12864b is not initialized\n");
-
goto none;
-
}
-
-
if (cfag12864b_enable()) {
-
printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
-
"can't enable cfag12864b refreshing (being used)\n");
-
return -ENODEV;
-
}
-
-
ret = platform_driver_register(&cfag12864bfb_driver);
-
-
if (!ret) {
-
cfag12864bfb_device =
-
platform_device_alloc(CFAG12864BFB_NAME, 0);
-
-
if (cfag12864bfb_device)
-
ret = platform_device_add(cfag12864bfb_device);
-
else
-
ret = -ENOMEM;
-
-
if (ret) {
-
platform_device_put(cfag12864bfb_device);
-
platform_driver_unregister(&cfag12864bfb_driver);
-
}
-
}
-
-
none:
-
return ret;
-
}
-
-
static void __exit cfag12864bfb_exit(void)
-
{
-
platform_device_unregister(cfag12864bfb_device);
-
platform_driver_unregister(&cfag12864bfb_driver);
-
cfag12864b_disable();
-
}
-
-
module_init(cfag12864bfb_init);
-
module_exit(cfag12864bfb_exit);
-
-
MODULE_LICENSE("GPL v2");
-
MODULE_AUTHOR("Miguel Ojeda Sandonis ");
-
MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver");
阅读(2493) | 评论(0) | 转发(0) |