代码示例_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 待续。。。
原文地址:https://www.cnblogs.com/panda-w/p/10992943.html