LCOV - code coverage report
Current view: top level - drivers/video - amba-clcd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 355 0.0 %
Date: 2014-02-18 Functions: 0 23 0.0 %
Branches: 0 184 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  linux/drivers/video/amba-clcd.c
       3                 :            :  *
       4                 :            :  * Copyright (C) 2001 ARM Limited, by David A Rusling
       5                 :            :  * Updated to 2.5, Deep Blue Solutions Ltd.
       6                 :            :  *
       7                 :            :  * This file is subject to the terms and conditions of the GNU General Public
       8                 :            :  * License.  See the file COPYING in the main directory of this archive
       9                 :            :  * for more details.
      10                 :            :  *
      11                 :            :  *  ARM PrimeCell PL110 Color LCD Controller
      12                 :            :  */
      13                 :            : #include <linux/dma-mapping.h>
      14                 :            : #include <linux/module.h>
      15                 :            : #include <linux/kernel.h>
      16                 :            : #include <linux/errno.h>
      17                 :            : #include <linux/string.h>
      18                 :            : #include <linux/slab.h>
      19                 :            : #include <linux/delay.h>
      20                 :            : #include <linux/dma-mapping.h>
      21                 :            : #include <linux/memblock.h>
      22                 :            : #include <linux/mm.h>
      23                 :            : #include <linux/of.h>
      24                 :            : #include <linux/fb.h>
      25                 :            : #include <linux/init.h>
      26                 :            : #include <linux/ioport.h>
      27                 :            : #include <linux/list.h>
      28                 :            : #include <linux/amba/bus.h>
      29                 :            : #include <linux/amba/clcd.h>
      30                 :            : #include <linux/clk.h>
      31                 :            : #include <linux/hardirq.h>
      32                 :            : 
      33                 :            : #include <asm/sizes.h>
      34                 :            : 
      35                 :            : #define to_clcd(info)   container_of(info, struct clcd_fb, fb)
      36                 :            : 
      37                 :            : #ifdef CONFIG_ARM
      38                 :            : #define clcdfb_dma_alloc        dma_alloc_writecombine
      39                 :            : #define clcdfb_dma_free         dma_free_writecombine
      40                 :            : #define clcdfb_dma_mmap         dma_mmap_writecombine
      41                 :            : #else
      42                 :            : #define clcdfb_dma_alloc        dma_alloc_coherent
      43                 :            : #define clcdfb_dma_free         dma_free_coherent
      44                 :            : #define clcdfb_dma_mmap         dma_mmap_coherent
      45                 :            : #endif
      46                 :            : 
      47                 :            : /* This is limited to 16 characters when displayed by X startup */
      48                 :            : static const char *clcd_name = "CLCD FB";
      49                 :            : 
      50                 :            : /*
      51                 :            :  * Unfortunately, the enable/disable functions may be called either from
      52                 :            :  * process or IRQ context, and we _need_ to delay.  This is _not_ good.
      53                 :            :  */
      54                 :            : static inline void clcdfb_sleep(unsigned int ms)
      55                 :            : {
      56 [ #  # ][ #  # ]:          0 :         if (in_atomic()) {
      57 [ #  # ][ #  # ]:          0 :                 mdelay(ms);
      58                 :            :         } else {
      59                 :          0 :                 msleep(ms);
      60                 :            :         }
      61                 :            : }
      62                 :            : 
      63                 :            : static inline void clcdfb_set_start(struct clcd_fb *fb)
      64                 :            : {
      65                 :          0 :         unsigned long ustart = fb->fb.fix.smem_start;
      66                 :            :         unsigned long lstart;
      67                 :            : 
      68                 :          0 :         ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
      69                 :          0 :         lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
      70                 :            : 
      71                 :          0 :         writel(ustart, fb->regs + CLCD_UBAS);
      72                 :          0 :         writel(lstart, fb->regs + CLCD_LBAS);
      73                 :            : }
      74                 :            : 
      75                 :          0 : static void clcdfb_disable(struct clcd_fb *fb)
      76                 :            : {
      77                 :            :         u32 val;
      78                 :            : 
      79         [ #  # ]:          0 :         if (fb->board->disable)
      80                 :          0 :                 fb->board->disable(fb);
      81                 :            : 
      82                 :          0 :         val = readl(fb->regs + fb->off_cntl);
      83         [ #  # ]:          0 :         if (val & CNTL_LCDPWR) {
      84                 :          0 :                 val &= ~CNTL_LCDPWR;
      85                 :          0 :                 writel(val, fb->regs + fb->off_cntl);
      86                 :            : 
      87                 :            :                 clcdfb_sleep(20);
      88                 :            :         }
      89         [ #  # ]:          0 :         if (val & CNTL_LCDEN) {
      90                 :          0 :                 val &= ~CNTL_LCDEN;
      91                 :          0 :                 writel(val, fb->regs + fb->off_cntl);
      92                 :            :         }
      93                 :            : 
      94                 :            :         /*
      95                 :            :          * Disable CLCD clock source.
      96                 :            :          */
      97         [ #  # ]:          0 :         if (fb->clk_enabled) {
      98                 :          0 :                 fb->clk_enabled = false;
      99                 :          0 :                 clk_disable(fb->clk);
     100                 :            :         }
     101                 :          0 : }
     102                 :            : 
     103                 :          0 : static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
     104                 :            : {
     105                 :            :         /*
     106                 :            :          * Enable the CLCD clock source.
     107                 :            :          */
     108         [ #  # ]:          0 :         if (!fb->clk_enabled) {
     109                 :          0 :                 fb->clk_enabled = true;
     110                 :          0 :                 clk_enable(fb->clk);
     111                 :            :         }
     112                 :            : 
     113                 :            :         /*
     114                 :            :          * Bring up by first enabling..
     115                 :            :          */
     116                 :          0 :         cntl |= CNTL_LCDEN;
     117                 :          0 :         writel(cntl, fb->regs + fb->off_cntl);
     118                 :            : 
     119                 :            :         clcdfb_sleep(20);
     120                 :            : 
     121                 :            :         /*
     122                 :            :          * and now apply power.
     123                 :            :          */
     124                 :          0 :         cntl |= CNTL_LCDPWR;
     125                 :          0 :         writel(cntl, fb->regs + fb->off_cntl);
     126                 :            : 
     127                 :            :         /*
     128                 :            :          * finally, enable the interface.
     129                 :            :          */
     130         [ #  # ]:          0 :         if (fb->board->enable)
     131                 :          0 :                 fb->board->enable(fb);
     132                 :          0 : }
     133                 :            : 
     134                 :            : static int
     135                 :          0 : clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
     136                 :            : {
     137                 :            :         u32 caps;
     138                 :            :         int ret = 0;
     139                 :            : 
     140 [ #  # ][ #  # ]:          0 :         if (fb->panel->caps && fb->board->caps)
     141                 :          0 :                 caps = fb->panel->caps & fb->board->caps;
     142                 :            :         else {
     143                 :            :                 /* Old way of specifying what can be used */
     144         [ #  # ]:          0 :                 caps = fb->panel->cntl & CNTL_BGR ?
     145                 :            :                         CLCD_CAP_BGR : CLCD_CAP_RGB;
     146                 :            :                 /* But mask out 444 modes as they weren't supported */
     147                 :          0 :                 caps &= ~CLCD_CAP_444;
     148                 :            :         }
     149                 :            : 
     150                 :            :         /* Only TFT panels can do RGB888/BGR888 */
     151         [ #  # ]:          0 :         if (!(fb->panel->cntl & CNTL_LCDTFT))
     152                 :          0 :                 caps &= ~CLCD_CAP_888;
     153                 :            : 
     154                 :          0 :         memset(&var->transp, 0, sizeof(var->transp));
     155                 :            : 
     156                 :          0 :         var->red.msb_right = 0;
     157                 :          0 :         var->green.msb_right = 0;
     158                 :          0 :         var->blue.msb_right = 0;
     159                 :            : 
     160 [ #  # ][ #  # ]:          0 :         switch (var->bits_per_pixel) {
         [ #  # ][ #  # ]
     161                 :            :         case 1:
     162                 :            :         case 2:
     163                 :            :         case 4:
     164                 :            :         case 8:
     165                 :            :                 /* If we can't do 5551, reject */
     166                 :          0 :                 caps &= CLCD_CAP_5551;
     167         [ #  # ]:          0 :                 if (!caps) {
     168                 :            :                         ret = -EINVAL;
     169                 :            :                         break;
     170                 :            :                 }
     171                 :            : 
     172                 :          0 :                 var->red.length              = var->bits_per_pixel;
     173                 :          0 :                 var->red.offset              = 0;
     174                 :          0 :                 var->green.length    = var->bits_per_pixel;
     175                 :          0 :                 var->green.offset    = 0;
     176                 :          0 :                 var->blue.length     = var->bits_per_pixel;
     177                 :          0 :                 var->blue.offset     = 0;
     178                 :            :                 break;
     179                 :            : 
     180                 :            :         case 16:
     181                 :            :                 /* If we can't do 444, 5551 or 565, reject */
     182         [ #  # ]:          0 :                 if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
     183                 :            :                         ret = -EINVAL;
     184                 :            :                         break;
     185                 :            :                 }
     186                 :            : 
     187                 :            :                 /*
     188                 :            :                  * Green length can be 4, 5 or 6 depending whether
     189                 :            :                  * we're operating in 444, 5551 or 565 mode.
     190                 :            :                  */
     191 [ #  # ][ #  # ]:          0 :                 if (var->green.length == 4 && caps & CLCD_CAP_444)
     192                 :            :                         caps &= CLCD_CAP_444;
     193 [ #  # ][ #  # ]:          0 :                 if (var->green.length == 5 && caps & CLCD_CAP_5551)
     194                 :            :                         caps &= CLCD_CAP_5551;
     195 [ #  # ][ #  # ]:          0 :                 else if (var->green.length == 6 && caps & CLCD_CAP_565)
     196                 :            :                         caps &= CLCD_CAP_565;
     197                 :            :                 else {
     198                 :            :                         /*
     199                 :            :                          * PL110 officially only supports RGB555,
     200                 :            :                          * but may be wired up to allow RGB565.
     201                 :            :                          */
     202         [ #  # ]:          0 :                         if (caps & CLCD_CAP_565) {
     203                 :          0 :                                 var->green.length = 6;
     204                 :            :                                 caps &= CLCD_CAP_565;
     205         [ #  # ]:          0 :                         } else if (caps & CLCD_CAP_5551) {
     206                 :          0 :                                 var->green.length = 5;
     207                 :            :                                 caps &= CLCD_CAP_5551;
     208                 :            :                         } else {
     209                 :          0 :                                 var->green.length = 4;
     210                 :          0 :                                 caps &= CLCD_CAP_444;
     211                 :            :                         }
     212                 :            :                 }
     213                 :            : 
     214         [ #  # ]:          0 :                 if (var->green.length >= 5) {
     215                 :          0 :                         var->red.length = 5;
     216                 :          0 :                         var->blue.length = 5;
     217                 :            :                 } else {
     218                 :          0 :                         var->red.length = 4;
     219                 :          0 :                         var->blue.length = 4;
     220                 :            :                 }
     221                 :            :                 break;
     222                 :            :         case 32:
     223                 :            :                 /* If we can't do 888, reject */
     224                 :          0 :                 caps &= CLCD_CAP_888;
     225         [ #  # ]:          0 :                 if (!caps) {
     226                 :            :                         ret = -EINVAL;
     227                 :            :                         break;
     228                 :            :                 }
     229                 :            : 
     230                 :          0 :                 var->red.length = 8;
     231                 :          0 :                 var->green.length = 8;
     232                 :          0 :                 var->blue.length = 8;
     233                 :            :                 break;
     234                 :            :         default:
     235                 :            :                 ret = -EINVAL;
     236                 :            :                 break;
     237                 :            :         }
     238                 :            : 
     239                 :            :         /*
     240                 :            :          * >= 16bpp displays have separate colour component bitfields
     241                 :            :          * encoded in the pixel data.  Calculate their position from
     242                 :            :          * the bitfield length defined above.
     243                 :            :          */
     244 [ #  # ][ #  # ]:          0 :         if (ret == 0 && var->bits_per_pixel >= 16) {
     245                 :            :                 bool bgr, rgb;
     246                 :            : 
     247 [ #  # ][ #  # ]:          0 :                 bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
     248 [ #  # ][ #  # ]:          0 :                 rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
     249                 :            : 
     250         [ #  # ]:          0 :                 if (!bgr && !rgb)
     251                 :            :                         /*
     252                 :            :                          * The requested format was not possible, try just
     253                 :            :                          * our capabilities.  One of BGR or RGB must be
     254                 :            :                          * supported.
     255                 :            :                          */
     256                 :          0 :                         bgr = caps & CLCD_CAP_BGR;
     257                 :            : 
     258         [ #  # ]:          0 :                 if (bgr) {
     259                 :          0 :                         var->blue.offset = 0;
     260                 :          0 :                         var->green.offset = var->blue.offset + var->blue.length;
     261                 :          0 :                         var->red.offset = var->green.offset + var->green.length;
     262                 :            :                 } else {
     263                 :          0 :                         var->red.offset = 0;
     264                 :          0 :                         var->green.offset = var->red.offset + var->red.length;
     265                 :          0 :                         var->blue.offset = var->green.offset + var->green.length;
     266                 :            :                 }
     267                 :            :         }
     268                 :            : 
     269                 :          0 :         return ret;
     270                 :            : }
     271                 :            : 
     272                 :          0 : static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
     273                 :            : {
     274                 :          0 :         struct clcd_fb *fb = to_clcd(info);
     275                 :            :         int ret = -EINVAL;
     276                 :            : 
     277         [ #  # ]:          0 :         if (fb->board->check)
     278                 :          0 :                 ret = fb->board->check(fb, var);
     279                 :            : 
     280 [ #  # ][ #  # ]:          0 :         if (ret == 0 &&
     281                 :          0 :             var->xres_virtual * var->bits_per_pixel / 8 *
     282                 :          0 :             var->yres_virtual > fb->fb.fix.smem_len)
     283                 :            :                 ret = -EINVAL;
     284                 :            : 
     285         [ #  # ]:          0 :         if (ret == 0)
     286                 :          0 :                 ret = clcdfb_set_bitfields(fb, var);
     287                 :            : 
     288                 :          0 :         return ret;
     289                 :            : }
     290                 :            : 
     291                 :          0 : static int clcdfb_set_par(struct fb_info *info)
     292                 :            : {
     293                 :            :         struct clcd_fb *fb = to_clcd(info);
     294                 :            :         struct clcd_regs regs;
     295                 :            : 
     296                 :          0 :         fb->fb.fix.line_length = fb->fb.var.xres_virtual *
     297                 :          0 :                                  fb->fb.var.bits_per_pixel / 8;
     298                 :            : 
     299         [ #  # ]:          0 :         if (fb->fb.var.bits_per_pixel <= 8)
     300                 :          0 :                 fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
     301                 :            :         else
     302                 :          0 :                 fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
     303                 :            : 
     304                 :          0 :         fb->board->decode(fb, &regs);
     305                 :            : 
     306                 :          0 :         clcdfb_disable(fb);
     307                 :            : 
     308                 :          0 :         writel(regs.tim0, fb->regs + CLCD_TIM0);
     309                 :          0 :         writel(regs.tim1, fb->regs + CLCD_TIM1);
     310                 :          0 :         writel(regs.tim2, fb->regs + CLCD_TIM2);
     311                 :          0 :         writel(regs.tim3, fb->regs + CLCD_TIM3);
     312                 :            : 
     313                 :            :         clcdfb_set_start(fb);
     314                 :            : 
     315                 :          0 :         clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
     316                 :            : 
     317                 :          0 :         fb->clcd_cntl = regs.cntl;
     318                 :            : 
     319                 :          0 :         clcdfb_enable(fb, regs.cntl);
     320                 :            : 
     321                 :            : #ifdef DEBUG
     322                 :            :         printk(KERN_INFO
     323                 :            :                "CLCD: Registers set to\n"
     324                 :            :                "  %08x %08x %08x %08x\n"
     325                 :            :                "  %08x %08x %08x %08x\n",
     326                 :            :                 readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
     327                 :            :                 readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
     328                 :            :                 readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
     329                 :            :                 readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
     330                 :            : #endif
     331                 :            : 
     332                 :          0 :         return 0;
     333                 :            : }
     334                 :            : 
     335                 :            : static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
     336                 :            : {
     337                 :          0 :         unsigned int mask = (1 << bf->length) - 1;
     338                 :            : 
     339                 :          0 :         return (val >> (16 - bf->length) & mask) << bf->offset;
     340                 :            : }
     341                 :            : 
     342                 :            : /*
     343                 :            :  *  Set a single color register. The values supplied have a 16 bit
     344                 :            :  *  magnitude.  Return != 0 for invalid regno.
     345                 :            :  */
     346                 :            : static int
     347                 :          0 : clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
     348                 :            :                  unsigned int blue, unsigned int transp, struct fb_info *info)
     349                 :            : {
     350                 :            :         struct clcd_fb *fb = to_clcd(info);
     351                 :            : 
     352         [ #  # ]:          0 :         if (regno < 16)
     353                 :          0 :                 fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
     354                 :          0 :                                   convert_bitfield(blue, &fb->fb.var.blue) |
     355                 :          0 :                                   convert_bitfield(green, &fb->fb.var.green) |
     356                 :          0 :                                   convert_bitfield(red, &fb->fb.var.red);
     357                 :            : 
     358 [ #  # ][ #  # ]:          0 :         if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
     359                 :          0 :                 int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
     360                 :            :                 u32 val, mask, newval;
     361                 :            : 
     362                 :          0 :                 newval  = (red >> 11)  & 0x001f;
     363                 :          0 :                 newval |= (green >> 6) & 0x03e0;
     364                 :          0 :                 newval |= (blue >> 1)  & 0x7c00;
     365                 :            : 
     366                 :            :                 /*
     367                 :            :                  * 3.2.11: if we're configured for big endian
     368                 :            :                  * byte order, the palette entries are swapped.
     369                 :            :                  */
     370         [ #  # ]:          0 :                 if (fb->clcd_cntl & CNTL_BEBO)
     371                 :          0 :                         regno ^= 1;
     372                 :            : 
     373         [ #  # ]:          0 :                 if (regno & 1) {
     374                 :          0 :                         newval <<= 16;
     375                 :            :                         mask = 0x0000ffff;
     376                 :            :                 } else {
     377                 :            :                         mask = 0xffff0000;
     378                 :            :                 }
     379                 :            : 
     380                 :          0 :                 val = readl(fb->regs + hw_reg) & mask;
     381                 :          0 :                 writel(val | newval, fb->regs + hw_reg);
     382                 :            :         }
     383                 :            : 
     384                 :          0 :         return regno > 255;
     385                 :            : }
     386                 :            : 
     387                 :            : /*
     388                 :            :  *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
     389                 :            :  *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
     390                 :            :  *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
     391                 :            :  *  to e.g. a video mode which doesn't support it. Implements VESA suspend
     392                 :            :  *  and powerdown modes on hardware that supports disabling hsync/vsync:
     393                 :            :  *    blank_mode == 2: suspend vsync
     394                 :            :  *    blank_mode == 3: suspend hsync
     395                 :            :  *    blank_mode == 4: powerdown
     396                 :            :  */
     397                 :          0 : static int clcdfb_blank(int blank_mode, struct fb_info *info)
     398                 :            : {
     399                 :            :         struct clcd_fb *fb = to_clcd(info);
     400                 :            : 
     401         [ #  # ]:          0 :         if (blank_mode != 0) {
     402                 :          0 :                 clcdfb_disable(fb);
     403                 :            :         } else {
     404                 :          0 :                 clcdfb_enable(fb, fb->clcd_cntl);
     405                 :            :         }
     406                 :          0 :         return 0;
     407                 :            : }
     408                 :            : 
     409                 :          0 : int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
     410                 :            : {
     411                 :          0 :         return clcdfb_dma_mmap(&fb->dev->dev, vma,
     412                 :          0 :                                fb->fb.screen_base,
     413                 :          0 :                                fb->fb.fix.smem_start,
     414                 :            :                                fb->fb.fix.smem_len);
     415                 :            : }
     416                 :            : 
     417                 :          0 : int clcdfb_mmap_io(struct clcd_fb *fb, struct vm_area_struct *vma)
     418                 :            : {
     419                 :            :         unsigned long user_count, count, pfn, off;
     420                 :            : 
     421                 :          0 :         user_count      = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
     422                 :          0 :         count           = PAGE_ALIGN(fb->fb.fix.smem_len) >> PAGE_SHIFT;
     423                 :          0 :         pfn             = fb->fb.fix.smem_start >> PAGE_SHIFT;
     424                 :          0 :         off             = vma->vm_pgoff;
     425                 :            : 
     426                 :          0 :         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
     427                 :            : 
     428 [ #  # ][ #  # ]:          0 :         if (off < count && user_count <= (count - off))
     429                 :          0 :                 return remap_pfn_range(vma, vma->vm_start, pfn + off,
     430                 :            :                                        user_count << PAGE_SHIFT,
     431                 :            :                                        vma->vm_page_prot);
     432                 :            : 
     433                 :            :         return -ENXIO;
     434                 :            : }
     435                 :            : 
     436                 :          0 : void clcdfb_remove_dma(struct clcd_fb *fb)
     437                 :            : {
     438                 :          0 :         clcdfb_dma_free(&fb->dev->dev, fb->fb.fix.smem_len,
     439                 :          0 :                         fb->fb.screen_base, fb->fb.fix.smem_start);
     440                 :          0 : }
     441                 :            : 
     442                 :          0 : void clcdfb_remove_io(struct clcd_fb *fb)
     443                 :            : {
     444                 :          0 :         iounmap(fb->fb.screen_base);
     445                 :          0 : }
     446                 :            : 
     447                 :          0 : static int clcdfb_mmap(struct fb_info *info,
     448                 :            :                        struct vm_area_struct *vma)
     449                 :            : {
     450                 :            :         struct clcd_fb *fb = to_clcd(info);
     451                 :          0 :         unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
     452                 :            :         int ret = -EINVAL;
     453                 :            : 
     454                 :          0 :         len = info->fix.smem_len;
     455                 :            : 
     456 [ #  # ][ #  # ]:          0 :         if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
                 [ #  # ]
     457                 :          0 :             fb->board->mmap)
     458                 :          0 :                 ret = fb->board->mmap(fb, vma);
     459                 :            : 
     460                 :          0 :         return ret;
     461                 :            : }
     462                 :            : 
     463                 :            : static struct fb_ops clcdfb_ops = {
     464                 :            :         .owner          = THIS_MODULE,
     465                 :            :         .fb_check_var   = clcdfb_check_var,
     466                 :            :         .fb_set_par     = clcdfb_set_par,
     467                 :            :         .fb_setcolreg   = clcdfb_setcolreg,
     468                 :            :         .fb_blank       = clcdfb_blank,
     469                 :            :         .fb_fillrect    = cfb_fillrect,
     470                 :            :         .fb_copyarea    = cfb_copyarea,
     471                 :            :         .fb_imageblit   = cfb_imageblit,
     472                 :            :         .fb_mmap        = clcdfb_mmap,
     473                 :            : };
     474                 :            : 
     475                 :          0 : static int clcdfb_register(struct clcd_fb *fb)
     476                 :            : {
     477                 :            :         int ret;
     478                 :            : 
     479                 :            :         /*
     480                 :            :          * ARM PL111 always has IENB at 0x1c; it's only PL110
     481                 :            :          * which is reversed on some platforms.
     482                 :            :          */
     483 [ #  # ][ #  # ]:          0 :         if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
     484                 :          0 :                 fb->off_ienb = CLCD_PL111_IENB;
     485                 :          0 :                 fb->off_cntl = CLCD_PL111_CNTL;
     486                 :            :         } else {
     487                 :            : #ifdef CONFIG_ARCH_VERSATILE
     488                 :            :                 fb->off_ienb = CLCD_PL111_IENB;
     489                 :            :                 fb->off_cntl = CLCD_PL111_CNTL;
     490                 :            : #else
     491                 :          0 :                 fb->off_ienb = CLCD_PL110_IENB;
     492                 :          0 :                 fb->off_cntl = CLCD_PL110_CNTL;
     493                 :            : #endif
     494                 :            :         }
     495                 :            : 
     496                 :          0 :         fb->clk = clk_get(&fb->dev->dev, NULL);
     497         [ #  # ]:          0 :         if (IS_ERR(fb->clk)) {
     498                 :            :                 ret = PTR_ERR(fb->clk);
     499                 :          0 :                 goto out;
     500                 :            :         }
     501                 :            : 
     502                 :          0 :         ret = clk_prepare(fb->clk);
     503         [ #  # ]:          0 :         if (ret)
     504                 :            :                 goto free_clk;
     505                 :            : 
     506                 :          0 :         fb->fb.device                = &fb->dev->dev;
     507                 :            : 
     508                 :          0 :         fb->fb.fix.mmio_start        = fb->dev->res.start;
     509                 :          0 :         fb->fb.fix.mmio_len  = resource_size(&fb->dev->res);
     510                 :            : 
     511                 :          0 :         fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
     512         [ #  # ]:          0 :         if (!fb->regs) {
     513                 :          0 :                 printk(KERN_ERR "CLCD: unable to remap registers\n");
     514                 :            :                 ret = -ENOMEM;
     515                 :          0 :                 goto clk_unprep;
     516                 :            :         }
     517                 :            : 
     518                 :          0 :         fb->fb.fbops         = &clcdfb_ops;
     519                 :          0 :         fb->fb.flags         = FBINFO_FLAG_DEFAULT;
     520                 :          0 :         fb->fb.pseudo_palette        = fb->cmap;
     521                 :            : 
     522                 :          0 :         strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
     523                 :          0 :         fb->fb.fix.type              = FB_TYPE_PACKED_PIXELS;
     524                 :          0 :         fb->fb.fix.type_aux  = 0;
     525                 :          0 :         fb->fb.fix.xpanstep  = 0;
     526                 :          0 :         fb->fb.fix.ypanstep  = 0;
     527                 :          0 :         fb->fb.fix.ywrapstep = 0;
     528                 :          0 :         fb->fb.fix.accel     = FB_ACCEL_NONE;
     529                 :            : 
     530                 :          0 :         fb->fb.var.xres              = fb->panel->mode.xres;
     531                 :          0 :         fb->fb.var.yres              = fb->panel->mode.yres;
     532                 :          0 :         fb->fb.var.xres_virtual      = fb->panel->mode.xres;
     533                 :          0 :         fb->fb.var.yres_virtual      = fb->panel->mode.yres;
     534                 :          0 :         fb->fb.var.bits_per_pixel = fb->panel->bpp;
     535                 :          0 :         fb->fb.var.grayscale = fb->panel->grayscale;
     536                 :          0 :         fb->fb.var.pixclock  = fb->panel->mode.pixclock;
     537                 :          0 :         fb->fb.var.left_margin       = fb->panel->mode.left_margin;
     538                 :          0 :         fb->fb.var.right_margin      = fb->panel->mode.right_margin;
     539                 :          0 :         fb->fb.var.upper_margin      = fb->panel->mode.upper_margin;
     540                 :          0 :         fb->fb.var.lower_margin      = fb->panel->mode.lower_margin;
     541                 :          0 :         fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
     542                 :          0 :         fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
     543                 :          0 :         fb->fb.var.sync              = fb->panel->mode.sync;
     544                 :          0 :         fb->fb.var.vmode     = fb->panel->mode.vmode;
     545                 :          0 :         fb->fb.var.activate  = FB_ACTIVATE_NOW;
     546                 :          0 :         fb->fb.var.nonstd    = 0;
     547                 :          0 :         fb->fb.var.height    = fb->panel->height;
     548                 :          0 :         fb->fb.var.width     = fb->panel->width;
     549                 :          0 :         fb->fb.var.accel_flags       = 0;
     550                 :            : 
     551                 :          0 :         fb->fb.monspecs.hfmin        = 0;
     552                 :          0 :         fb->fb.monspecs.hfmax   = 100000;
     553                 :          0 :         fb->fb.monspecs.vfmin        = 0;
     554                 :          0 :         fb->fb.monspecs.vfmax        = 400;
     555                 :          0 :         fb->fb.monspecs.dclkmin = 1000000;
     556                 :          0 :         fb->fb.monspecs.dclkmax      = 100000000;
     557                 :            : 
     558                 :            :         /*
     559                 :            :          * Make sure that the bitfields are set appropriately.
     560                 :            :          */
     561                 :          0 :         clcdfb_set_bitfields(fb, &fb->fb.var);
     562                 :            : 
     563                 :            :         /*
     564                 :            :          * Allocate colourmap.
     565                 :            :          */
     566                 :          0 :         ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
     567         [ #  # ]:          0 :         if (ret)
     568                 :            :                 goto unmap;
     569                 :            : 
     570                 :            :         /*
     571                 :            :          * Ensure interrupts are disabled.
     572                 :            :          */
     573                 :          0 :         writel(0, fb->regs + fb->off_ienb);
     574                 :            : 
     575                 :          0 :         fb_set_var(&fb->fb, &fb->fb.var);
     576                 :            : 
     577                 :          0 :         dev_info(&fb->dev->dev, "%s hardware, %s display\n",
     578                 :            :                  fb->board->name, fb->panel->mode.name);
     579                 :            : 
     580                 :          0 :         ret = register_framebuffer(&fb->fb);
     581         [ #  # ]:          0 :         if (ret == 0)
     582                 :            :                 goto out;
     583                 :            : 
     584                 :          0 :         printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
     585                 :            : 
     586                 :          0 :         fb_dealloc_cmap(&fb->fb.cmap);
     587                 :            :  unmap:
     588                 :          0 :         iounmap(fb->regs);
     589                 :            :  clk_unprep:
     590                 :          0 :         clk_unprepare(fb->clk);
     591                 :            :  free_clk:
     592                 :          0 :         clk_put(fb->clk);
     593                 :            :  out:
     594                 :          0 :         return ret;
     595                 :            : }
     596                 :            : 
     597                 :            : struct string_lookup {
     598                 :            :         const char *string;
     599                 :            :         const u32       val;
     600                 :            : };
     601                 :            : 
     602                 :            : static struct string_lookup vmode_lookups[] = {
     603                 :            :         { "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
     604                 :            :         { "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
     605                 :            :         { "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
     606                 :            :         { "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
     607                 :            :         { NULL, 0 },
     608                 :            : };
     609                 :            : 
     610                 :            : static struct string_lookup tim2_lookups[] = {
     611                 :            :         { "TIM2_CLKSEL", TIM2_CLKSEL},
     612                 :            :         { "TIM2_IVS",    TIM2_IVS},
     613                 :            :         { "TIM2_IHS",    TIM2_IHS},
     614                 :            :         { "TIM2_IPC",    TIM2_IPC},
     615                 :            :         { "TIM2_IOE",    TIM2_IOE},
     616                 :            :         { "TIM2_BCD",    TIM2_BCD},
     617                 :            :         { NULL, 0},
     618                 :            : };
     619                 :            : static struct string_lookup cntl_lookups[] = {
     620                 :            :         {"CNTL_LCDEN",        CNTL_LCDEN},
     621                 :            :         {"CNTL_LCDBPP1",      CNTL_LCDBPP1},
     622                 :            :         {"CNTL_LCDBPP2",      CNTL_LCDBPP2},
     623                 :            :         {"CNTL_LCDBPP4",      CNTL_LCDBPP4},
     624                 :            :         {"CNTL_LCDBPP8",      CNTL_LCDBPP8},
     625                 :            :         {"CNTL_LCDBPP16",     CNTL_LCDBPP16},
     626                 :            :         {"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
     627                 :            :         {"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
     628                 :            :         {"CNTL_LCDBPP24",     CNTL_LCDBPP24},
     629                 :            :         {"CNTL_LCDBW",        CNTL_LCDBW},
     630                 :            :         {"CNTL_LCDTFT",       CNTL_LCDTFT},
     631                 :            :         {"CNTL_LCDMONO8",     CNTL_LCDMONO8},
     632                 :            :         {"CNTL_LCDDUAL",      CNTL_LCDDUAL},
     633                 :            :         {"CNTL_BGR",          CNTL_BGR},
     634                 :            :         {"CNTL_BEBO",         CNTL_BEBO},
     635                 :            :         {"CNTL_BEPO",         CNTL_BEPO},
     636                 :            :         {"CNTL_LCDPWR",       CNTL_LCDPWR},
     637                 :            :         {"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
     638                 :            :         {"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
     639                 :            :         {"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
     640                 :            :         {"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
     641                 :            :         {"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
     642                 :            :         {"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
     643                 :            :         {"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
     644                 :            :         {"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
     645                 :            :         {"CNTL_WATERMARK",    CNTL_WATERMARK},
     646                 :            :         { NULL, 0},
     647                 :            : };
     648                 :            : static struct string_lookup caps_lookups[] = {
     649                 :            :         {"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
     650                 :            :         {"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
     651                 :            :         {"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
     652                 :            :         {"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
     653                 :            :         {"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
     654                 :            :         {"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
     655                 :            :         {"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
     656                 :            :         {"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
     657                 :            :         {"CLCD_CAP_444",     CLCD_CAP_444},
     658                 :            :         {"CLCD_CAP_5551",    CLCD_CAP_5551},
     659                 :            :         {"CLCD_CAP_565",     CLCD_CAP_565},
     660                 :            :         {"CLCD_CAP_888",     CLCD_CAP_888},
     661                 :            :         {"CLCD_CAP_RGB",     CLCD_CAP_RGB},
     662                 :            :         {"CLCD_CAP_BGR",     CLCD_CAP_BGR},
     663                 :            :         {"CLCD_CAP_ALL",     CLCD_CAP_ALL},
     664                 :            :         { NULL, 0},
     665                 :            : };
     666                 :            : 
     667                 :          0 : u32 parse_setting(struct string_lookup *lookup, const char *name)
     668                 :            : {
     669                 :            :         int i = 0;
     670         [ #  # ]:          0 :         while (lookup[i].string != NULL) {
     671         [ #  # ]:          0 :                 if (strcmp(lookup[i].string, name) == 0)
     672                 :          0 :                         return lookup[i].val;
     673                 :          0 :                 ++i;
     674                 :            :         }
     675                 :            :         return -EINVAL;
     676                 :            : }
     677                 :            : 
     678                 :          0 : u32 get_string_lookup(struct device_node *node, const char *name,
     679                 :            :                       struct string_lookup *lookup)
     680                 :            : {
     681                 :            :         const char *string;
     682                 :            :         int count, i, ret = 0;
     683                 :            : 
     684                 :          0 :         count = of_property_count_strings(node, name);
     685         [ #  # ]:          0 :         if (count >= 0)
     686         [ #  # ]:          0 :                 for (i = 0; i < count; i++)
     687         [ #  # ]:          0 :                         if (of_property_read_string_index(node, name, i,
     688                 :            :                                         &string) == 0)
     689                 :          0 :                                 ret |= parse_setting(lookup, string);
     690                 :          0 :         return ret;
     691                 :            : }
     692                 :            : 
     693                 :          0 : int get_val(struct device_node *node, const char *string)
     694                 :            : {
     695                 :          0 :         u32 ret = 0;
     696                 :            : 
     697         [ #  # ]:          0 :         if (of_property_read_u32(node, string, &ret))
     698                 :          0 :                 ret = -1;
     699                 :          0 :         return ret;
     700                 :            : }
     701                 :            : 
     702                 :          0 : struct clcd_panel *getPanel(struct device_node *node)
     703                 :            : {
     704                 :            :         static struct clcd_panel panel;
     705                 :            : 
     706                 :          0 :         panel.mode.refresh      = get_val(node, "refresh");
     707                 :          0 :         panel.mode.xres         = get_val(node, "xres");
     708                 :          0 :         panel.mode.yres         = get_val(node, "yres");
     709                 :          0 :         panel.mode.pixclock     = get_val(node, "pixclock");
     710                 :          0 :         panel.mode.left_margin  = get_val(node, "left_margin");
     711                 :          0 :         panel.mode.right_margin = get_val(node, "right_margin");
     712                 :          0 :         panel.mode.upper_margin = get_val(node, "upper_margin");
     713                 :          0 :         panel.mode.lower_margin = get_val(node, "lower_margin");
     714                 :          0 :         panel.mode.hsync_len    = get_val(node, "hsync_len");
     715                 :          0 :         panel.mode.vsync_len    = get_val(node, "vsync_len");
     716                 :          0 :         panel.mode.sync         = get_val(node, "sync");
     717                 :          0 :         panel.bpp               = get_val(node, "bpp");
     718                 :          0 :         panel.width             = (signed short) get_val(node, "width");
     719                 :          0 :         panel.height            = (signed short) get_val(node, "height");
     720                 :            : 
     721                 :          0 :         panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
     722                 :          0 :         panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
     723                 :          0 :         panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
     724                 :          0 :         panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
     725                 :            : 
     726                 :          0 :         return &panel;
     727                 :            : }
     728                 :            : 
     729                 :          0 : struct clcd_panel *clcdfb_get_panel(const char *name)
     730                 :            : {
     731                 :            :         struct device_node *node = NULL;
     732                 :            :         const char *mode;
     733                 :            :         struct clcd_panel *panel = NULL;
     734                 :            : 
     735                 :            :         do {
     736                 :          0 :                 node = of_find_compatible_node(node, NULL, "panel");
     737         [ #  # ]:          0 :                 if (node)
     738         [ #  # ]:          0 :                         if (of_property_read_string(node, "mode", &mode) == 0)
     739         [ #  # ]:          0 :                                 if (strcmp(mode, name) == 0) {
     740                 :          0 :                                         panel = getPanel(node);
     741                 :          0 :                                         panel->mode.name = name;
     742                 :            :                                 }
     743         [ #  # ]:          0 :         } while (node != NULL);
     744                 :            : 
     745                 :          0 :         return panel;
     746                 :            : }
     747                 :            : 
     748                 :            : #ifdef CONFIG_OF
     749                 :          0 : static int clcdfb_dt_init(struct clcd_fb *fb)
     750                 :            : {
     751                 :            :         int err = 0;
     752                 :            :         struct device_node *node;
     753                 :            :         const char *mode;
     754                 :            :         dma_addr_t dma;
     755                 :            :         u32 use_dma;
     756                 :            :         const __be32 *prop;
     757                 :            :         int len, na, ns;
     758                 :            :         phys_addr_t fb_base, fb_size;
     759                 :            : 
     760                 :          0 :         node = fb->dev->dev.of_node;
     761         [ #  # ]:          0 :         if (!node)
     762                 :            :                 return -ENODEV;
     763                 :            : 
     764                 :          0 :         na = of_n_addr_cells(node);
     765                 :          0 :         ns = of_n_size_cells(node);
     766                 :            : 
     767 [ #  # ][ #  # ]:          0 :         if (WARN_ON(of_property_read_string(node, "mode", &mode)))
     768                 :            :                 return -ENODEV;
     769                 :            : 
     770                 :          0 :         fb->panel = clcdfb_get_panel(mode);
     771         [ #  # ]:          0 :         if (!fb->panel)
     772                 :            :                 return -EINVAL;
     773                 :          0 :         fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
     774                 :            : 
     775                 :          0 :         fb->board->name           = "Device Tree CLCD PL111";
     776                 :          0 :         fb->board->caps           = CLCD_CAP_5551 | CLCD_CAP_565;
     777                 :          0 :         fb->board->check  = clcdfb_check;
     778                 :          0 :         fb->board->decode = clcdfb_decode;
     779                 :            : 
     780         [ #  # ]:          0 :         if (of_property_read_u32(node, "use_dma", &use_dma))
     781                 :          0 :                 use_dma = 0;
     782                 :            : 
     783         [ #  # ]:          0 :         if (use_dma) {
     784                 :          0 :                 fb->fb.screen_base = clcdfb_dma_alloc(&fb->dev->dev,
     785                 :            :                                                       fb->fb.fix.smem_len,
     786                 :            :                                                       &dma, GFP_KERNEL);
     787         [ #  # ]:          0 :                 if (!fb->fb.screen_base) {
     788                 :          0 :                         pr_err("CLCD: unable to map framebuffer\n");
     789                 :          0 :                         return -ENOMEM;
     790                 :            :                 }
     791                 :            : 
     792                 :          0 :                 fb->fb.fix.smem_start        = dma;
     793                 :          0 :                 fb->board->mmap           = clcdfb_mmap_dma;
     794                 :          0 :                 fb->board->remove = clcdfb_remove_dma;
     795                 :            :         } else {
     796                 :          0 :                 prop = of_get_property(node, "framebuffer", &len);
     797 [ #  # ][ #  # ]:          0 :                 if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
         [ #  # ][ #  # ]
     798                 :            :                         return -EINVAL;
     799                 :            : 
     800                 :          0 :                 fb_base = of_read_number(prop, na);
     801                 :          0 :                 fb_size = of_read_number(prop + na, ns);
     802                 :            : 
     803                 :          0 :                 fb->fb.fix.smem_start        = fb_base;
     804                 :          0 :                 fb->fb.screen_base   = ioremap_wc(fb_base, fb_size);
     805                 :          0 :                 fb->board->mmap           = clcdfb_mmap_io;
     806                 :          0 :                 fb->board->remove = clcdfb_remove_io;
     807                 :            :         }
     808                 :            : 
     809                 :            :         return err;
     810                 :            : }
     811                 :            : #endif /* CONFIG_OF */
     812                 :            : 
     813                 :          0 : static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
     814                 :            : {
     815                 :          0 :         struct clcd_board *board = dev_get_platdata(&dev->dev);
     816                 :            :         struct clcd_fb *fb;
     817                 :            :         int ret;
     818                 :            : 
     819         [ #  # ]:          0 :         if (!board) {
     820                 :            : #ifdef CONFIG_OF
     821         [ #  # ]:          0 :                 if (dev->dev.of_node) {
     822                 :            :                         board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
     823         [ #  # ]:          0 :                         if (!board)
     824                 :            :                                 return -ENOMEM;
     825                 :          0 :                         board->setup   = clcdfb_dt_init;
     826                 :            :                 } else
     827                 :            : #endif
     828                 :            :                         return -EINVAL;
     829                 :            :         }
     830                 :            : 
     831                 :          0 :         ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
     832         [ #  # ]:          0 :         if (ret)
     833                 :            :                 goto out;
     834                 :            : 
     835                 :          0 :         ret = amba_request_regions(dev, NULL);
     836         [ #  # ]:          0 :         if (ret) {
     837                 :          0 :                 printk(KERN_ERR "CLCD: unable to reserve regs region\n");
     838                 :          0 :                 goto out;
     839                 :            :         }
     840                 :            : 
     841                 :            :         fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
     842         [ #  # ]:          0 :         if (!fb) {
     843                 :          0 :                 printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
     844                 :            :                 ret = -ENOMEM;
     845                 :          0 :                 goto free_region;
     846                 :            :         }
     847                 :            : 
     848                 :          0 :         fb->dev = dev;
     849                 :          0 :         fb->board = board;
     850                 :            : 
     851                 :          0 :         dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n",
     852                 :            :                 amba_part(dev), amba_rev(dev),
     853                 :            :                 (unsigned long long)dev->res.start);
     854                 :            : 
     855                 :          0 :         ret = fb->board->setup(fb);
     856         [ #  # ]:          0 :         if (ret)
     857                 :            :                 goto free_fb;
     858                 :            : 
     859                 :          0 :         ret = clcdfb_register(fb); 
     860         [ #  # ]:          0 :         if (ret == 0) {
     861                 :          0 :                 amba_set_drvdata(dev, fb);
     862                 :          0 :                 goto out;
     863                 :            :         }
     864                 :            : 
     865                 :          0 :         fb->board->remove(fb);
     866                 :            :  free_fb:
     867                 :          0 :         kfree(fb);
     868                 :            :  free_region:
     869                 :          0 :         amba_release_regions(dev);
     870                 :            :  out:
     871                 :          0 :         return ret;
     872                 :            : }
     873                 :            : 
     874                 :          0 : static int clcdfb_remove(struct amba_device *dev)
     875                 :            : {
     876                 :          0 :         struct clcd_fb *fb = amba_get_drvdata(dev);
     877                 :            : 
     878                 :          0 :         clcdfb_disable(fb);
     879                 :          0 :         unregister_framebuffer(&fb->fb);
     880         [ #  # ]:          0 :         if (fb->fb.cmap.len)
     881                 :          0 :                 fb_dealloc_cmap(&fb->fb.cmap);
     882                 :          0 :         iounmap(fb->regs);
     883                 :          0 :         clk_unprepare(fb->clk);
     884                 :          0 :         clk_put(fb->clk);
     885                 :            : 
     886                 :          0 :         fb->board->remove(fb);
     887                 :            : 
     888                 :          0 :         kfree(fb);
     889                 :            : 
     890                 :          0 :         amba_release_regions(dev);
     891                 :            : 
     892                 :          0 :         return 0;
     893                 :            : }
     894                 :            : 
     895                 :            : static struct amba_id clcdfb_id_table[] = {
     896                 :            :         {
     897                 :            :                 .id     = 0x00041110,
     898                 :            :                 .mask   = 0x000ffffe,
     899                 :            :         },
     900                 :            :         { 0, 0 },
     901                 :            : };
     902                 :            : 
     903                 :            : MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
     904                 :            : 
     905                 :            : static struct amba_driver clcd_driver = {
     906                 :            :         .drv            = {
     907                 :            :                 .name   = "clcd-pl11x",
     908                 :            :         },
     909                 :            :         .probe          = clcdfb_probe,
     910                 :            :         .remove         = clcdfb_remove,
     911                 :            :         .id_table       = clcdfb_id_table,
     912                 :            : };
     913                 :            : 
     914                 :          0 : static int __init amba_clcdfb_init(void)
     915                 :            : {
     916         [ #  # ]:          0 :         if (fb_get_options("ambafb", NULL))
     917                 :            :                 return -ENODEV;
     918                 :            : 
     919                 :          0 :         return amba_driver_register(&clcd_driver);
     920                 :            : }
     921                 :            : 
     922                 :            : module_init(amba_clcdfb_init);
     923                 :            : 
     924                 :          0 : static void __exit amba_clcdfb_exit(void)
     925                 :            : {
     926                 :          0 :         amba_driver_unregister(&clcd_driver);
     927                 :          0 : }
     928                 :            : 
     929                 :            : module_exit(amba_clcdfb_exit);
     930                 :            : 
     931                 :            : MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
     932                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.9