• 代码示例_LCD控制



      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/errno.h>
      4 #include <linux/string.h>
      5 #include <linux/mm.h>
      6 #include <linux/slab.h>
      7 #include <linux/delay.h>
      8 #include <linux/fb.h>
      9 #include <linux/init.h>
     10 #include <linux/dma-mapping.h>
     11 #include <linux/interrupt.h>
     12 #include <linux/workqueue.h>
     13 #include <linux/wait.h>
     14 #include <linux/platform_device.h>
     15 #include <linux/clk.h> 
     16 #include <asm/io.h>
     17 #include <asm/uaccess.h>
     18 #include <asm/div64.h> 
     19 #include <asm/mach/map.h>
     20 #include <asm/types.h>
     21 
     22 #define LCD_BASE 0x11400000
     23 #define LCD_F0 (LCD_BASE+0x0180)
     24 #define LCD_F1 (LCD_BASE+0x01A0)
     25 #define LCD_F2 (LCD_BASE+0x01C0)
     26 #define LCD_F3 (LCD_BASE+0x01E0)
     27 #define LCD_PWM (LCD_BASE+0x00A0)
     28 #define LCD_PWM_BASE 0x139D0000
     29 #define LCD_PWM_TCFG0 (LCD_PWM_BASE+0x0000)
     30 #define LCD_PWM_TCFG1 (LCD_PWM_BASE+0x0004)
     31 #define LCD_PWM_TCON  (LCD_PWM_BASE+0x0008)
     32 #define LCD_PWM_TCNTB1 (LCD_PWM_BASE+0x0018)
     33 #define LCD_PWM_TCMPB1 (LCD_PWM_BASE+0x001C)
     34 
     35 #define BLK_FLAG 1
     36 
     37  //模块信息
     38 
     39  MODULE_LICENSE("Dual BSD/GPL");
     40 
     41 
     42 
     43 static struct fb_info * my_fbInfo = NULL;
     44 static int myLcdBpp = 32;//位深
     45 static short myPaletteSize = 256; //调色板大小
     46 static unsigned int myXvSize = 1024; //缓冲列大小
     47 static unsigned int myYvSize = 768; //缓冲行大小
     48 static unsigned int pseudo_palette [16];//调色板数组,被fb_info->pseudo_palette调用
     49 
     50 //IO管脚寄存器
     51 static unsigned int * __iomem gpf0con;
     52 static unsigned int * __iomem gpf1con;
     53 static unsigned int * __iomem gpf2con;
     54 static unsigned int * __iomem gpf3con;
     55 static unsigned int * __iomem gpd0con;//pwm控制
     56 static unsigned int * __iomem gpd0dat;
     57 
     58 //pwm寄存器
     59 static unsigned int * __iomem tcfg0;
     60 static unsigned int * __iomem tcfg1;
     61 static unsigned int * __iomem tcon;
     62 static unsigned int * __iomem tcntb1;
     63 static unsigned int * __iomem tcmpb1;
     64 
     65 //时钟相关寄存器
     66 static unsigned int * __iomem clk_div_lcd;//lcd时钟分频
     67 static unsigned int * __iomem clk_src_lcd0;//lcd时钟源
     68 static unsigned int * __iomem lcdblk_cfg;//显示控制寄存器
     69 static unsigned int * __iomem lcdblk_cfg2;//显示控制寄存器
     70 
     71 //lcd寄存器
     72 static unsigned int * __iomem vidcon0;//Configures video output format and displays enable/disable.
     73 static unsigned int * __iomem vidcon1;//Specifies RGB I/F control signal
     74 static unsigned int * __iomem vidcon2;//Specifies output data format control.
     75 static unsigned int * __iomem vidtcon0;//Configures video output timing and determines the size of display
     76 static unsigned int * __iomem vidtcon1;//Configures video output timing and determines the size of display
     77 static unsigned int * __iomem vidtcon2;//Configures video output timing and determines the size of display
     78 static unsigned int * __iomem wincon0;//Specifies window0 feature setting
     79 static unsigned int * __iomem vidoso0a;//Specifies window position setting
     80 static unsigned int * __iomem vidoso0b;//Specifies window position setting
     81 static unsigned int * __iomem vidoso0c;//Specifies On Screen Display (OSD) size setting.
     82 static unsigned int * __iomem shaadowcon;//Specifies shadow control register
     83 static unsigned int * __iomem winchmap2;//Specifies window color control
     84 static unsigned int * __iomem vidw00add0b0;//Specifies source image address setting
     85 static unsigned int * __iomem vidw00add1b0;//Specifies source image address setting
     86 static unsigned int * __iomem win0map;//Specifies window color control
     87 static unsigned int * __iomem vidw00add2;//Specifies source image address setting
     88 
     89 ////static T_LCD_REG * __iomem lcdBase;
     90 /* from pxafb.c */
     91 /*
     92 struct fb_bitfield {  //fb缓存的RGB位域,该结构描述每一个像素显示缓冲区的组织方式,
     93                     //假如为RGB565模式,R占5位=bit[11:15]G占6位=bit[10:5] B占5位=bit[4:0]
     94   __u32 offset;     // beginning of bitfield 位域偏移:red=11 ,green=5 blue=0
     95   __u32 length;   // length of bitfield  位域长度 red=5 green=6 blue=5 
     96   __u32 msb_right;//!= 0 : Most significant bit is */  /*msb_right!=0=>MSB在右边 
     97  }; 
     98  
     99 */ 
    100 
    101 static inline unsigned int chan_to_field(unsigned int chan,struct fb_bitfield *bf)
    102 {    
    103     /*内核中的单色都是16位,默认从左到右排列,比如G颜色[0x1f],那么chan就等于0XF800*/
    104     chan&= 0xffff;
    105     chan >>= 16 - bf->length;//右移,将数据靠到位0上
    106     return chan << bf->offset;//左移一定偏移值,放入16色数据中对应的位置
    107 }
    108 
    109 ////设置调色板函数,供内核调用
    110 static int my_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info)
    111 {
    112     unsigned int val = 0;
    113     //用red,green,blue三个颜色值构造出16色数据val
    114     switch(info->fix.visual){
    115            case FB_VISUAL_TRUECOLOR: //true-color,use pseudo_palette
    116                         if(regno < 16){
    117                                 u32 *pal = info-> pseudo_palette;
    118                                 val  = chan_to_field(red,&info->var.red);
    119                                 val |= chan_to_field(green,&info->var.green);
    120                                 val |= chan_to_field(blue,&info->var.blue);
    121                                 pal[regno] = val;
    122                         }
    123                         break;
    124            default :
    125                     return 1; // 未知类型
    126     }
    127 
    128     return 0;
    129 
    130 }
    131 
    132 static struct fb_ops my_fb_ops = {
    133             .owner = THIS_MODULE,
    134             .fb_setcolreg = my_fb_setcolreg,//调用my_lcdfb_setcolreg()函数,来设置调色板fb_info-> pseudo_palette
    135             .fb_fillrect = cfb_fillrect,//填充矩形
    136             .fb_copyarea = cfb_copyarea,//复制数据
    137             .fb_imageblit = cfb_imageblit,//绘画图形
    138 };
    139 
    140 //设置可变参数
    141 static int fb_fill_var(struct fb_info *myfb)
    142 {
    143     myfb->var.activate = FB_ACTIVATE_NOW;
    144     myfb->var.vmode = FB_VMODE_NONINTERLACED;
    145     myfb->var.bits_per_pixel = myLcdBpp;/*每个像素的位数即BPP,比如:RGB565则填入16*/
    146     myfb->var.xres_virtual = myXvSize;/*虚拟屏幕一行有多少个像素点 */
    147     myfb->var.yres_virtual = myYvSize;/*虚拟屏幕一列有多少个像素点*/
    148     myfb->var.xres = myXvSize;/*可见屏幕一行有多少个像素点*/
    149     myfb->var.yres = myYvSize;/*可见屏幕一列有多少个像素点*/
    150     myfb->var.xoffset = 0;/*虚拟到可见屏幕之间的行偏移,若可见和虚拟的分辨率一样,就直接设为0*/
    151     myfb->var.yoffset = 0;/*虚拟到可见屏幕之间的列偏移*/
    152 
    153     //保持透明度参数为0
    154     myfb->var.transp.offset = 0;
    155     myfb->var.transp.length = 0;
    156     switch(myfb->var.bits_per_pixel){
    157             case 1:
    158             case 2:
    159             case 4:
    160             case 8:
    161                 /* non palletised, A:1,R:2,G:3,B:2 mode */
    162                 myfb->var.red.offset = 5;
    163                 myfb->var.green.offset = 2;
    164                 myfb->var.blue.offset = 0;
    165                 myfb->var.red.length = 2;
    166                 myfb->var.green.length = 3;
    167                 myfb->var.blue.length = 2;
    168                 myfb->var.transp.offset = 7;
    169                 myfb->var.transp.length = 1;
    170                 break;
    171             case 19:
    172                 /* 666 with one bit alpha/transparency */
    173                 myfb->var.transp.offset = 18;
    174                 myfb->var.transp.length = 1;
    175                 /* drop through */
    176             case 18:
    177                 myfb->var.bits_per_pixel = 32;
    178                 /* 666 format */
    179                 myfb->var.red.offset = 12;
    180                 myfb->var.green.offset = 6;
    181                 myfb->var.blue.offset = 0;
    182                 myfb->var.red.length = 6;
    183                 myfb->var.green.length = 6;
    184                 myfb->var.blue.length = 6;
    185                 break;
    186             case 16:
    187                 /* 16 bpp, 565 format */
    188                 myfb->var.red.offset = 11;
    189                 myfb->var.green.offset = 5;
    190                 myfb->var.blue.offset = 0;
    191                 myfb->var.red.length = 5;
    192                 myfb->var.green.length = 6;
    193                 myfb->var.blue.length = 5;
    194                 break;
    195             case 32:
    196             case 28:
    197             case 25:
    198                 myfb->var.transp.length = myfb-> var.bits_per_pixel - 24;
    199                 myfb->var.transp.offset = 24;
    200                 /* drop through */
    201             case 24:
    202                 /* our 24bpp is unpacked, so 32bpp */
    203                 myfb->var.bits_per_pixel = 32;
    204                 myfb->var.red.offset = 16;
    205                 myfb->var.red.length = 8;
    206                 myfb->var.green.offset = 8;
    207                 myfb->var.green.length = 8;
    208                 myfb->var.blue.offset = 0;
    209                 myfb->var.blue.length = 8;
    210                 break;
    211             default:
    212                 printk("invalid bpp
    ");
    213                 return -EINVAL;
    214     }
    215     return 0;
    216 }
    217 
    218 //设置固定参数
    219 static int fb_fill_fix(struct fb_info *myfb)
    220 {
    221     unsigned int real_size,virt_size,size;
    222     dma_addr_t map_dma;
    223     strcpy(myfb->fix.id,"mylcd");
    224     myfb->fix.type = FB_TYPE_PACKED_PIXELS; //在该方式下,像素值与内存直接对应
    225     myfb->fix.accel = FB_ACCEL_NONE;
    226     myfb->fix.line_length =(myfb->var.xres_virtual * myfb->var.bits_per_pixel)/8;//一行的大小(字节数)
    227     myfb->fix.xpanstep = myfb->var.xres_virtual> myfb->var.xres?1:0;/*如果没有硬件panning就赋值为0 */
    228     myfb->fix.ypanstep = myfb->var.yres_virtual> myfb->var.yres?1:0;/*如果没有硬件panning就赋值为0 */
    229      //fix.visual画面设置,常用参数如下
    230     // FB_VISUAL_MONO01             0   单色,0:白色,1:黑色
    231     // FB_VISUAL_MONO10             1    单色,1:白色,0:黑色
    232     // FB_VISUAL_TRUECOLOR          2     真彩(TFT:真彩)
    233     // FB_VISUAL_PSEUDOCOLOR        3     伪彩
    234     // FB_VISUAL_DIRECTCOLOR        4     直彩
    235     switch(myfb->var.bits_per_pixel){
    236         case 32:
    237         case 24:
    238         case 16:
    239         case 12:
    240             myfb->fix.visual = FB_VISUAL_TRUECOLOR;
    241             break;
    242         case 8:
    243             if(myPaletteSize >= 256)
    244                 myfb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
    245             else
    246                 myfb->fix.visual = FB_VISUAL_TRUECOLOR;
    247             break;
    248         case 1:
    249             myfb->fix.visual = FB_VISUAL_MONO01;
    250             break;
    251         default:
    252             myfb->fix.visual = FB_VISUAL_TRUECOLOR;
    253             break;
    254     }
    255 
    256      /*计算整体缓冲大小*/
    257     real_size = myfb->var.xres * myfb->var.yres;
    258     virt_size = myfb->var.xres_virtual * myfb->var.yres_virtual;
    259     size =(real_size > virt_size)?real_size:virt_size;
    260     size *=(myfb->var.bits_per_pixel > 16)?32:myLcdBpp;
    261 
    262     size /= 8;
    263     myfb->fix.smem_len = size;//framebuffer长度,字节为单位
    264     size = PAGE_ALIGN(size);
    265     //显存虚拟起始地址,把地址告诉LCD控制器和fb_info
    266     //void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);  //分配DMA缓存区给显存
    267     //返回值为:申请到的DMA缓冲区的虚拟地址,若为NULL,表示分配失败,则需要使用dma_free_writecombine()释放内存,避免内存泄漏
    268     //参数如下: 
    269     //*dev:指针,这里填0,表示这个申请的缓冲区里没有内容
    270     //size:分配的地址大小(字节单位)
    271     //*handle:申请到的物理起始地址
    272     //gfp:分配出来的内存参数,标志定义在<linux/gfp.h>,常用标志如下:
    273     //GFP_ATOMIC    用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
    274     //GFP_KERNEL    内核内存的正常分配. 可能睡眠.
    275     //GFP_USER      用来为用户空间页来分配内存; 它可能睡眠. 
    276     myfb->screen_base = dma_alloc_writecombine(myfb->dev, size,&map_dma, GFP_KERNEL);
    277     if(!myfb->screen_base){
    278         return -ENOMEM;
    279     }
    280     memset(myfb->screen_base,0x0,size);
    281     myfb->fix.smem_start = map_dma;
    282     return 0;
    283 }
    284 
    285 static void myfb_Init(struct fb_info *myfb)
    286 {
    287     /*varinit*/
    288     fb_fill_var(myfb);
    289     /*fix init*/
    290     fb_fill_fix(myfb);
    291     /*ops init*/
    292     myfb->fbops =&my_fb_ops;
    293     /*ops init*/
    294     myfb->flags = FBINFO_FLAG_DEFAULT;
    295     myfb->pseudo_palette = pseudo_palette;//保存调色板数组
    296 }
    297 
    298 static void mygpio_Init(void)
    299 {
    300     gpf0con = ioremap(LCD_F0,4);
    301     gpf1con = ioremap(LCD_F1,4);
    302     gpf2con = ioremap(LCD_F2,4);
    303     gpf3con = ioremap(LCD_F3,4);
    304     writel(0x22222222,gpf0con);
    305     writel(0x22222222,gpf1con);
    306     writel(0x22222222,gpf2con);
    307     *gpf3con &=~(0xffff);
    308     writel(0x2222,gpf3con);
    309 
    310     //背光
    311     if(BLK_FLAG)//pwm方式
    312     {
    313         gpd0con = ioremap(LCD_PWM,4);
    314         writel((readl(gpd0con) & (~(0xf<<4))) | (0x2<<4) , gpd0con);
    315     }
    316     else //直接点亮方式
    317     {
    318         int val;
    319     //    unsigned int * __iomem gpd0con;
    320     //    unsigned int * __iomem gpd0dat;
    321     
    322         gpd0con = ioremap(0x114000A0,4);
    323         gpd0dat = ioremap(0x114000A4,4);
    324         
    325         val = readl(gpd0con);
    326         val &=~(0xf<<4);
    327         val |=(0x1<<4);
    328         writel(val,gpd0con);
    329         val = readl(gpd0dat);
    330         val|=(0x1<<1);
    331         writel(val,gpd0dat);
    332     }
    333 }
    334 
    335 static void myclk_Init(void)
    336 {
    337     clk_div_lcd = ioremap(0x1003c534,4);
    338     clk_src_lcd0 = ioremap(0x1003c234,4);
    339     lcdblk_cfg = ioremap(0x10010210,4);
    340     lcdblk_cfg2 = ioremap(0x10010214,4);
    341 
    342     /*时钟源选择MPLL具体参考<Exyons 4412 datasheet pg526>
    343     *CLK_DIV_LCD:
    344     *[3:0]:FIMD0_RATIO   0
    345     *SCLK_FIMD0 = MOUTFIMD0/(FIMD0_RATIO + 1)=800M/1 = 800M
    346 
    347     *<Exyons 4412 datasheet pg501>
    348     *CLK_SRC_LCD0:
    349     *[3:0]:FIMD0_SEL 0110 ===>0x6 SCLKmpll_user_t 选择时钟源为SCLKmpll_user_t
    350     */
    351     writel(readl(clk_div_lcd)&~0xf,clk_div_lcd);
    352     writel((readl(clk_src_lcd0)&~0xf)|0x6,clk_src_lcd0);
    353 
    354     /*<Exyons 4412 datasheet pg1767>
    355     *Using the display controller data, you can select one of the above data paths by
    356     *setting LCDBLK_CFG Register (0x1001_0210). For more information, refer to the "System Others" manual.
    357     *While using RGB interface, the VT_LBLKx bit fields in LCDBLKC_CFG (0x1001_0210) register should be set to
    358     *RGB Interface out (2'b00), even though you use DSI Video Mode.*/
    359 
    360     /*
    361     *<Exyons 4412 datasheet pg884>
    362     *LCDBLK_CFG:
    363     *           [1] : FIMD of LBLK0 Bypass Selection    1 : FIMD Bypass   使用FIMD接口
    364     *LCDBLK_CFG2:
    365     *            [0]:MIE0_DISPON     1 :  PWM outpupt enable 
    366     */
    367     writel((readl(lcdblk_cfg)&(~(0x3<<10)))|(1<<1),lcdblk_cfg);//set FIMD
    368   //writel(readl(lcdblk_cfg2)|(1<<0),lcdblk_cfg2); //set pwm
    369 
    370 }
    371 
    372 static void mypwm_Init(void)
    373 {
    374     tcfg0 = ioremap(LCD_PWM_TCFG0,4);
    375     tcfg1 = ioremap(LCD_PWM_TCFG1,4);
    376     tcon = ioremap(LCD_PWM_TCON,4);
    377     tcntb1 = ioremap(LCD_PWM_TCNTB1,4);
    378     tcmpb1 = ioremap(LCD_PWM_TCMPB1,4);
    379     
    380     /*占空比控制背光亮度*/
    381     writel((readl(tcfg0) &(~0xff))|0xff,tcfg0);
    382     writel((readl(tcfg1) &(~(0xf<<4)))|0x4<<4,tcfg1);
    383     writel(300,tcntb1);
    384     writel(150,tcmpb1);
    385     
    386     writel((readl(tcon)&(~(0xf<<8)))|(0x1<<9),tcon);
    387 
    388     //使能
    389     writel((readl(tcon)&(~(0x1<<9)))|(0x1<<8),tcon);
    390 
    391 }
    392 
    393 static int lcd_Init(struct fb_info *myfb)
    394 {
    395     unsigned int val;
    396     //lcd设置
    397     vidcon0 =ioremap(0x11c00000,0x4);
    398     vidcon1 =ioremap(0x11c00004,0x4);
    399     vidcon2 =ioremap(0x11c00008,0x4);
    400     vidtcon0 = ioremap(0x11c00010,0x4);
    401     vidtcon1 = ioremap(0x11c00014,0x4);
    402     vidtcon2 = ioremap(0x11c00018,0x4);
    403     win0map = ioremap(0x11C00180, 0x4);
    404     wincon0 = ioremap(0x11c00020, 0x4);
    405     vidoso0a = ioremap(0x11c00040,0x4);
    406     vidoso0b = ioremap(0x11c00044,0x4);
    407     vidoso0c = ioremap(0x11c00048,0x4);
    408     shaadowcon = ioremap(0x11c00034,0x4);
    409     winchmap2 =ioremap(0x11c0003c,0x4);
    410     vidw00add0b0 = ioremap(0x11c000a0,0x4);
    411     vidw00add1b0 = ioremap(0x11c000d0,0x4);
    412     vidw00add2 = ioremap(0x11C00104,0x4);
    413 
    414     /*HV mode fclk :44.9~63 推荐51.2Mhz 参考
    415     *vidcon0 [13-6] VCLK = FIMD*SCLK/(CLKVAL+1)
    416     *50M = 800M/(CLK_VAL+1) CLK_VAL= 15 这里为了取整,取50M
    417     *CLK_VAL为vidcon0 [13-6]这7位的十进制值,15为0001111,左移6位到[13-6],
    418     *注意并不是将13位转化为10进制,而是单独7位
    419     */
    420     //writel(15<<6, vidcon0);
    421     writel((15<<6|3), vidcon0);
    422     /*
    423     *:VSYNC,HSYNC高电平触发信号,VCLK上升沿开始传输数据
    424     *:VSD,HSD低电平触发信号,CLKV下降沿开始传输数据
    425     *
    426     * VIDCON1:
    427     * [5]:IVSYNC ===> 1 : Inverted(反转)
    428     * [6]:IHSYNC ===> 1 : Inverted(反转)
    429     * [7]:IVCLK ===> 1 : Fetches video data at VCLK rising edge (下降沿触发,反转?)
    430     * [10:9]:FIXVCLK ====> 01 : VCLK running�
    431     * */
    432     writel((1<<9)|(1<<7)|(1<<5)|(1<<6),vidcon1);
    433     //Reserved: This bit should be set to 1.
    434     writel(1<<14, vidcon2);
    435     
    436     /*参考 HV mode
    437     * thbp: 160 (DCLK)
    438     * thfp: 160 (DCLK)
    439     * thpw: 1-140 (DCLK)
    440     * tvpw: 1-20 (Th)
    441     * ttvbp: 23 (Th)
    442     * tvfp: 12 (Th)
    443     */
    444     /*
    445     *<Exyons 4412 datasheet pg1874 pg1848(时序)> <参考具体LCD屏参数(时序)>
    446     *VIDTCON0: 
    447     *         [23:16]:  VBPD + 1 <------> tvpw (1 - 20)    13
    448     *         [15:8]: VFPD + 1 <------> tvfp 22
    449     *         [7:0]: VSPW  + 1 <------> tvb - tvpw = 23 - 13 = 10
    450     **/
    451     /*VIDTCONx用来设置时序和长宽等参数,这里就主要设置VBPD(vertical back porch)、
    452      VFBD(vertical frontporch)、VSPW(vertical sync pulse width)、
    453     HBPD(horizontal backporch)、 HFPD(horizontal sync pul     se width)等参数
    454     */
    455     /*<Exyons 4412 datasheet pg1874 pg1848(时序)> <参考具体LCD屏参数(时序)>
    456      *VIDTCON1: 
    457      *       [23:16]:  HBPD + 1 <------> thpw (1 - 40)  36 
    458      *       [15:8]:   HFPD + 1 <------> thfp 210 
    459      *       [7:0]:    HSPW  + 1 <------> thb - thpw = 46 - 36 = 10
    460      */
    461 
    462 #define HSPW 31 //行同步
    463 #define HBPD 79
    464 #define HFPD 47
    465 #define VSPW 4 //帧同步
    466 #define VBPD 13
    467 #define VFPD 2
    468     writel(((VBPD <<16)|(VFPD <<8)|(VSPW <<0)),vidtcon0);
    469     writel(((HBPD <<16)|(HFPD <<8)|(HSPW <<0)),vidtcon1);
    470 
    471     /*设置大小,参考 Display Format Graphic 1024RGB*600 Dot-matrix
    472     * HOZVAL = (Horizontal display size) – 1 and LINEVAL = (Vertical display size) – 1.
    473     */
    474     writel(((1023<<0) | (599<<11)), vidtcon2);
    475 
    476     /*绑定win,这里直接使用了win0
    477     * TODO:0xd=32位,这里强行写的,具体需要参考实际情况写16,24或32
    478     */
    479     //writel((1<<6)|(0xD<<2)|1,wincon0);
    480     writel((1<<6)|(5<<2)|1,wincon0);
    481 
    482     /*LCD左上角坐标*/
    483     writel(0<<11|0, vidoso0a);
    484 
    485     /* LCD右下角坐标 参考
    486     * 24 BPP mode should have X position by 1 pixel. (For example, X = 0, 1, 2, 3….)
    487     * 16 BPP mode should have X position by 2 pixel. (For example, X = 0, 2, 4, 6….)
    488     * 8 BPP mode should have X position by 4 pixel. (For example, X = 0, 4, 8, 12….)
    489     */
    490     if(myLcdBpp == 16)
    491     {
    492         val = (((1023*2) <<11) | ((599*2) <<0));
    493     }
    494     else if((myLcdBpp == 24) || (myLcdBpp == 32))
    495     {
    496         val = (((1023) <<11) | ((599) <<0));
    497     }
    498     writel(val, vidoso0b);
    499 
    500     /*总大小*/
    501     writel(1024*600, vidoso0c);
    502 
    503     /*帧缓冲起始地址*/
    504     writel(myfb->fix.smem_start, vidw00add0b0);
    505 
    506     /*帧缓冲结束地址*/
    507     writel(myfb->fix.smem_start+myfb->fix.smem_len, vidw00add1b0);
    508 
    509     /*设置偏移和宽度*/
    510     writel((0<<13) | ((1024 * myLcdBpp / 8)<<0), vidw00add2);
    511 
    512     /*绑定通道和窗口*/
    513     writel(1, shaadowcon);
    514     writel((readl(winchmap2)&(~(0x7<<16))&(~0x7))|(1<<16)|(1<<0), winchmap2);
    515 
    516     /*Enables the video output and video control signal*/
    517     writel(readl(vidcon0)|0x3, vidcon0);
    518     return 0;
    519 }
    520 
    521 static int fs4412_lcd_init(void)
    522 {
    523     int ret = 0;
    524     /************************kernel相关*******************************/
    525     /**这部分参考s3c-fb.c**/
    526     /*申请fb_info*/
    527     my_fbInfo = framebuffer_alloc(0,NULL); //这里没有私有数据,所以是0;dev没有,平台驱动需要添加
    528 
    529     /*初始化fb_info*/
    530     myfb_Init(my_fbInfo);
    531     /************************硬件相关*******************************/
    532     /*管脚设置*/
    533     mygpio_Init();
    534     /*时钟设置*/
    535     myclk_Init();
    536     /*控制芯片设置*/
    537     mypwm_Init();
    538     lcd_Init(my_fbInfo);
    539 
    540 
    541     /*注册*/
    542     ret = register_framebuffer(my_fbInfo);
    543     if(0> ret){
    544         printk(KERN_ERR "failed to register framebuffer 
    ");
    545     //dma_free_coherent(fs_info->dev, fs_info->fix.smem_len,fs_info->screen_base, fs_info->fix.smem_start);
    546         return ret;
    547     }
    548     printk("Lcd init ok
    ");
    549     return 0;
    550 }
    551 
    552 
    553 static void fs4412_lcd_exit(void)
    554 {
    555     printk("Lcd exit
    ");
    556     unregister_framebuffer(my_fbInfo);
    557     iounmap(gpf0con);
    558     iounmap(gpf1con);
    559     iounmap(gpf2con);
    560     iounmap(gpf3con);
    561     //myfb->dev, size,&map_dma, GFP_KERNEL
    562 
    563     /*释放DMA缓存地址dma_free_writecombine()*/
    564     dma_free_writecombine(my_fbInfo->dev,my_fbInfo->screen_size,my_fbInfo->screen_base,my_fbInfo->fix.smem_start);
    565     framebuffer_release(my_fbInfo);
    566 }
    567 
    568 module_init(fs4412_lcd_init);
    569 module_exit(fs4412_lcd_exit);
      1 #include <unistd.h>
      2 #include <stdio.h>
      3 #include <fcntl.h>
      4 #include <linux/fb.h>
      5 #include <sys/mman.h>
      6 #include <errno.h>
      7 #include <stdlib.h>
      8 //#include "logo1.h"
      9 char *framebuffer_ptr;
     10 unsigned int xsize = 1024;
     11 unsigned int ysize = 600;
     12 unsigned int bpp = 16;
     13 void PutPixel(unsigned int x, unsigned int y, unsigned int color)
     14 {
     15     unsigned char red,green,blue;
     16     switch (bpp){
     17         case 16:
     18         {
     19             unsigned short *addr = (unsigned short *)framebuffer_ptr + (y * xsize + x);
     20             red   = (color >> 19) & 0x1f;
     21             green = (color >> 10) & 0x3f;
     22             blue  = (color >>  3) & 0x1f;
     23             color = (red << 11) | (green << 5) | blue; // 格式5:6:5
     24             *addr = (unsigned short) color;
     25             break;
     26         }
     27         
     28         case 8:
     29         {
     30             unsigned char *addr = (unsigned char *)framebuffer_ptr + (y * xsize + x);
     31             *addr = (unsigned char) color;
     32             break;
     33         }
     34 
     35         default:
     36             break;
     37     }
     38 }
     39 /* 
     40   * 绘制同心圆
     41   */
     42 void Mire(void)
     43 {
     44     unsigned long x,y;
     45     unsigned long color;
     46     unsigned char red,green,blue,alpha;
     47 
     48     for (y = 0; y < ysize; y++)
     49         for (x = 0; x < xsize; x++){
     50             color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;
     51             red   = (color/8) % 256;
     52             green = (color/4) % 256;
     53             blue  = (color/2) % 256;
     54             alpha = (color*2) % 256;
     55 
     56             color |= ((unsigned long)alpha << 24);
     57             color |= ((unsigned long)red   << 16);
     58             color |= ((unsigned long)green << 8 );
     59             color |= ((unsigned long)blue       );
     60 
     61             PutPixel(x,y,color);
     62         }
     63 }
     64 /* 
     65  * 将屏幕清成单色
     66  * 输入参数:
     67  *     color: 颜色值
     68  *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
     69  *     需要转换为5:6:5格式
     70  *         对于8BPP: color为调色板中的索引值,
     71  *     其颜色取决于调色板中的数值
     72  */
     73 void ClearScr(unsigned int color)
     74 {   
     75     unsigned long x,y;
     76     
     77     for (y = 0; y < ysize; y++)
     78         for (x = 0; x < xsize; x++)
     79             PutPixel(x, y, color);
     80 }
     81 int bmp2fb16_rgb565(unsigned char *bmpdata,unsigned short *fb16)
     82 {
     83     int x, y;
     84     unsigned short r, g, b;
     85     unsigned short pixel16;
     86     unsigned short * fb16_buff;
     87 
     88     fb16_buff = fb16;
     89     for(y = ysize-1; y >= 0 ; y--)
     90     {
     91         for (x = 0 ; x < xsize; x++) /*copy one line to frame buffer*/
     92         {    
     93             /*copy one pixel to frame buffer*/
     94             b = *bmpdata;
     95             bmpdata++;
     96             b >>= 3;
     97             g = *bmpdata;
     98             bmpdata++;
     99             g >>= 2;
    100             r = *bmpdata;
    101             bmpdata++;
    102             r >>= 3;
    103             pixel16 = (unsigned short)((r << 11) | (g << 5) | b);    
    104             *(fb16_buff + (y* xsize + x)) = pixel16;
    105         }
    106     }
    107     return 0;
    108 }
    109 
    110 int bmp_read_file(const char *bmpfilename,unsigned char **bmpdata)
    111 {
    112     int nread;
    113     int raw_size = 0;    
    114     *bmpdata = bmpfilename +(unsigned char)54;
    115     return 0;
    116 }
    117 
    118 void draw_bmp(char *bmpfilename, unsigned short *fb)
    119 {
    120     unsigned char * bmpdata;
    121     int ret;
    122 
    123     ret = bmp_read_file(bmpfilename, &bmpdata);
    124     if (ret)
    125     {
    126         printf("read bmpfile error.
    ");
    127     }
    128     printf("bmpread0000000!!!!
    ");
    129     bmp2fb16_rgb565(bmpdata, fb);
    130     printf("bm2fb1600000000000!!!!
    ");
    131 }
    132 //./lcd_test xxx.jpg
    133 int main(int argc,char **argv)
    134 {
    135     int fp = 0;
    136     struct fb_var_screeninfo   vinfo;
    137     struct fb_fix_screeninfo   finfo;
    138  
    139     int screensize = 0;
    140     //char *fbp = 0;
    141     //int x = 0, y = 0;
    142     //int location = 0;
    143     int bytes_per_pixel;
    144     int pic_fd;
    145     unsigned long len;
    146     unsigned char *buffer;
    147     int key;
    148     int i;
    149     
    150     /*1.打开一副图片*/
    151     pic_fd =open(argv[1],O_RDWR);
    152     printf("pic_fd=%d
    ",pic_fd);
    153 
    154     /*2.获取图片大小*/
    155     len =lseek(pic_fd, 0, SEEK_END);
    156     printf("len =%ld
    ",len);
    157 
    158     buffer =(unsigned char *)malloc(len);
    159 
    160     lseek(pic_fd, 0, SEEK_SET);
    161     /*3.读取图片数据*/
    162     read(pic_fd,buffer,len); 
    163 
    164  
    165     fp = open("/dev/fb0", O_RDWR);
    166     if(fp < 0) {
    167         printf("open failed
    ");
    168     }
    169  
    170     if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)) {
    171         perror("ioctl");
    172     }
    173  
    174     if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)) {
    175         perror("ioctl");
    176     }
    177  
    178     bytes_per_pixel = vinfo.bits_per_pixel/8;
    179     screensize = vinfo.xres * vinfo.yres * bytes_per_pixel;
    180     printf("x = %d  y = %d   bytes_per_pixel = %d
    ",  vinfo.xres,  vinfo.yres,  bytes_per_pixel);
    181     printf("screensize = %d
    ",  screensize);
    182  
    183     framebuffer_ptr = (char*) mmap(0,  screensize,  PROT_READ |PROT_WRITE,  MAP_SHARED, fp, 0);
    184     if(framebuffer_ptr < 0) {
    185         perror("mmap");
    186     }
    187     printf("line_length = %d
    ",finfo.line_length);
    188 #if 0
    189     for(x = 100; x<200; x++) {
    190         for(y=100; y<200; y++) {
    191             location = x * bytes_per_pixel + y * finfo.line_length;
    192             *(framebuffer_ptr + location) = 0;
    193             *(framebuffer_ptr +location + 1) = 255;
    194             *(framebuffer_ptr + location + 2) = 0;
    195             *(framebuffer_ptr + location + 3) = 0;
    196         }
    197     }
    198  #endif
    199 
    200     while(1)
    201     {
    202         /*2.图像处理*/
    203         scanf("%d",&key);
    204         switch(key)
    205         {
    206             case 1:
    207                 /*2.7 显示图片*/
    208                 printf("test picture!
    ");
    209                 
    210                 printf("loadjpeg00000!!!!
    ");
    211                 draw_bmp(buffer,(unsigned short *) framebuffer_ptr);
    212                 break;
    213             case 2:
    214                 ClearScr(0x00ff0000);
    215                 break;
    216             case 3:
    217                 Mire();
    218                 break;
    219             default:
    220                 break;
    221         }    
    222     }
    223     munmap(framebuffer_ptr, screensize);
    224     close(fp);
    225     return 0;
    226 }
     1 ROOTFS_DIR = /source/rootfs
     2 
     3 MODULE_NAME = lcd_drv
     4 APP_NAME = lcd_test
     5 
     6 CROSS_COMPILE = /home/kevin/Linux_4412/toolchain/gcc-4.6.4/bin/arm-none-linux-gnueabi-
     7 CC = $(CROSS_COMPILE)gcc
     8 
     9 ifeq ($(KERNELRELEASE), )
    10 
    11 KERNEL_DIR = /home/kevin/Linux_4412/linux-3.14-fs4412
    12 CUR_DIR = $(shell pwd)
    13 
    14 all :
    15     make -C  $(KERNEL_DIR) M=$(CUR_DIR) modules
    16     $(CC) $(APP_NAME).c  -o $(APP_NAME)
    17 
    18 clean :
    19     make -C  $(KERNEL_DIR) M=$(CUR_DIR) clean
    20     rm -rf $(APP_NAME)    
    21 
    22 install:
    23     cp -raf *.ko $(APP_NAME)   $(ROOTFS_DIR)/drv_module
    24 
    25 
    26 else
    27 
    28 obj-m += $(MODULE_NAME).o
    29 
    30 
    31 endif

    gt811的编程思路:
    1, 为gt811需要一个i2c client提供从设备信息

    arch/arm/mach-s5pv210/mach-smdkv210.c
    static struct i2c_board_info smdkv210_i2c_devs2[] __initdata = {
    /* To Be Updated */
    { I2C_BOARD_INFO("gt811_i2c_ts", 0x5d), },
    };

    make zImage -j2
    更新内核:
    cp -raf arch/arm/boot/zImage /tftpboot/

    2, 构建i2c_driver, 注册到总线
    实现probe()
    |
    1, 构建一个input device
    2, 初始化 input device
    3, 注册input device
    4, 硬件初始化:
    a, 上电初始化
    1, 设置中断引脚为悬浮输入态,RESET设置成GPIO(内部上拉)
    2, RESET引脚设置成输出低(开始复位), 延时1ms, 转成输入态
    3, 延迟至少20ms,通过i2c寻址gt811 (确认复位是否成功)
    4,如果有响应,分一次或者多次初始化寄存器
    5,如果没有响应,重复2步骤



    b, 申请中断--request_irq(), 还要用中断下半部(tasklet, 工作队列(选择这个))
    |
    1,通过i2c_tranfser(会导致休眠)读取到坐标
    2, 分析坐标
    3, 上报坐标
    ------------------------------------------------------------

    linux驱动中:对于多点触摸屏, 实际需要一个多点上报协议:

    Documentation/input$ ls multi-touch-protocol.txt

    Here is what a minimal event sequence for a two-contact touch would look
    like for a type A device:

    ABS_MT_POSITION_X x[0]
    ABS_MT_POSITION_Y y[0]
    SYN_MT_REPORT //第0点上报完毕
    ABS_MT_POSITION_X x[1]
    ABS_MT_POSITION_Y y[1]
    SYN_MT_REPORT //第1点上报完毕
    SYN_REPORT //所有点上报完毕


    在代码中实现:
    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_X, x);
    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_Y, y);
    input_mt_sync(gt811_dev->inputdev);
    |
    input_event(dev, EV_SYN, SYN_MT_REPORT, 0);

    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_X, x);
    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_Y, y);
    input_mt_sync(gt811_dev->inputdev);

    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_X, x);
    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_Y, y);
    input_mt_sync(gt811_dev->inputdev);

    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_X, x);
    input_event(gt811_dev->inputdev, EV_ABS, ABS_MT_POSITION_Y, y);
    input_mt_sync(gt811_dev->inputdev);

    input_sync(gt811_dev->inputdev); //所有点上报完毕

    Stay hungry, stay foolish 待续。。。
  • 相关阅读:
    android模拟器中文乱码
    Broadcast Receviewer
    Spring XML配置里的Bean自动装配
    Spring中的Bean配置
    Spring第一个helloWorld
    MyBatis向数据库中批量插入数据
    MyBatis联合查询和使用association 进行分步式查询
    MyBatis编写映射文件实现增删改操作 附说明及代码
    MyBatis全局配置文件MyBatis-config.xml代码
    MyBatis全局配置文件mybatis-config.xml
  • 原文地址:https://www.cnblogs.com/panda-w/p/10992943.html
Copyright © 2020-2023  润新知