linux 12864驱动程序,Linux 下LCD12864液晶驱动

内容介绍:之前有一个项目想要使用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 /* module */

#include /* file operation */

#include /* get_user() */

#include /* 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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值