Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc6 708 lines 17 kB view raw
1/* 2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 3 * JZ4740 SoC LCD framebuffer driver 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 * You should have received a copy of the GNU General Public License along 11 * with this program; if not, write to the Free Software Foundation, Inc., 12 * 675 Mass Ave, Cambridge, MA 02139, USA. 13 * 14 */ 15 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/mutex.h> 19#include <linux/platform_device.h> 20#include <linux/pinctrl/consumer.h> 21 22#include <linux/clk.h> 23#include <linux/delay.h> 24 25#include <linux/console.h> 26#include <linux/fb.h> 27 28#include <linux/dma-mapping.h> 29 30#include <asm/mach-jz4740/jz4740_fb.h> 31 32#define JZ_REG_LCD_CFG 0x00 33#define JZ_REG_LCD_VSYNC 0x04 34#define JZ_REG_LCD_HSYNC 0x08 35#define JZ_REG_LCD_VAT 0x0C 36#define JZ_REG_LCD_DAH 0x10 37#define JZ_REG_LCD_DAV 0x14 38#define JZ_REG_LCD_PS 0x18 39#define JZ_REG_LCD_CLS 0x1C 40#define JZ_REG_LCD_SPL 0x20 41#define JZ_REG_LCD_REV 0x24 42#define JZ_REG_LCD_CTRL 0x30 43#define JZ_REG_LCD_STATE 0x34 44#define JZ_REG_LCD_IID 0x38 45#define JZ_REG_LCD_DA0 0x40 46#define JZ_REG_LCD_SA0 0x44 47#define JZ_REG_LCD_FID0 0x48 48#define JZ_REG_LCD_CMD0 0x4C 49#define JZ_REG_LCD_DA1 0x50 50#define JZ_REG_LCD_SA1 0x54 51#define JZ_REG_LCD_FID1 0x58 52#define JZ_REG_LCD_CMD1 0x5C 53 54#define JZ_LCD_CFG_SLCD BIT(31) 55#define JZ_LCD_CFG_PS_DISABLE BIT(23) 56#define JZ_LCD_CFG_CLS_DISABLE BIT(22) 57#define JZ_LCD_CFG_SPL_DISABLE BIT(21) 58#define JZ_LCD_CFG_REV_DISABLE BIT(20) 59#define JZ_LCD_CFG_HSYNCM BIT(19) 60#define JZ_LCD_CFG_PCLKM BIT(18) 61#define JZ_LCD_CFG_INV BIT(17) 62#define JZ_LCD_CFG_SYNC_DIR BIT(16) 63#define JZ_LCD_CFG_PS_POLARITY BIT(15) 64#define JZ_LCD_CFG_CLS_POLARITY BIT(14) 65#define JZ_LCD_CFG_SPL_POLARITY BIT(13) 66#define JZ_LCD_CFG_REV_POLARITY BIT(12) 67#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11) 68#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10) 69#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) 70#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) 71#define JZ_LCD_CFG_18_BIT BIT(7) 72#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) 73#define JZ_LCD_CFG_MODE_MASK 0xf 74 75#define JZ_LCD_CTRL_BURST_4 (0x0 << 28) 76#define JZ_LCD_CTRL_BURST_8 (0x1 << 28) 77#define JZ_LCD_CTRL_BURST_16 (0x2 << 28) 78#define JZ_LCD_CTRL_RGB555 BIT(27) 79#define JZ_LCD_CTRL_OFUP BIT(26) 80#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) 81#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) 82#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) 83#define JZ_LCD_CTRL_PDD_MASK (0xff << 16) 84#define JZ_LCD_CTRL_EOF_IRQ BIT(13) 85#define JZ_LCD_CTRL_SOF_IRQ BIT(12) 86#define JZ_LCD_CTRL_OFU_IRQ BIT(11) 87#define JZ_LCD_CTRL_IFU0_IRQ BIT(10) 88#define JZ_LCD_CTRL_IFU1_IRQ BIT(9) 89#define JZ_LCD_CTRL_DD_IRQ BIT(8) 90#define JZ_LCD_CTRL_QDD_IRQ BIT(7) 91#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) 92#define JZ_LCD_CTRL_LSB_FISRT BIT(5) 93#define JZ_LCD_CTRL_DISABLE BIT(4) 94#define JZ_LCD_CTRL_ENABLE BIT(3) 95#define JZ_LCD_CTRL_BPP_1 0x0 96#define JZ_LCD_CTRL_BPP_2 0x1 97#define JZ_LCD_CTRL_BPP_4 0x2 98#define JZ_LCD_CTRL_BPP_8 0x3 99#define JZ_LCD_CTRL_BPP_15_16 0x4 100#define JZ_LCD_CTRL_BPP_18_24 0x5 101 102#define JZ_LCD_CMD_SOF_IRQ BIT(31) 103#define JZ_LCD_CMD_EOF_IRQ BIT(30) 104#define JZ_LCD_CMD_ENABLE_PAL BIT(28) 105 106#define JZ_LCD_SYNC_MASK 0x3ff 107 108#define JZ_LCD_STATE_DISABLED BIT(0) 109 110struct jzfb_framedesc { 111 uint32_t next; 112 uint32_t addr; 113 uint32_t id; 114 uint32_t cmd; 115} __packed; 116 117struct jzfb { 118 struct fb_info *fb; 119 struct platform_device *pdev; 120 void __iomem *base; 121 struct resource *mem; 122 struct jz4740_fb_platform_data *pdata; 123 124 size_t vidmem_size; 125 void *vidmem; 126 dma_addr_t vidmem_phys; 127 struct jzfb_framedesc *framedesc; 128 dma_addr_t framedesc_phys; 129 130 struct clk *ldclk; 131 struct clk *lpclk; 132 133 unsigned is_enabled:1; 134 struct mutex lock; 135 136 uint32_t pseudo_palette[16]; 137}; 138 139static const struct fb_fix_screeninfo jzfb_fix = { 140 .id = "JZ4740 FB", 141 .type = FB_TYPE_PACKED_PIXELS, 142 .visual = FB_VISUAL_TRUECOLOR, 143 .xpanstep = 0, 144 .ypanstep = 0, 145 .ywrapstep = 0, 146 .accel = FB_ACCEL_NONE, 147}; 148 149/* Based on CNVT_TOHW macro from skeletonfb.c */ 150static inline uint32_t jzfb_convert_color_to_hw(unsigned val, 151 struct fb_bitfield *bf) 152{ 153 return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset; 154} 155 156static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, 157 unsigned blue, unsigned transp, struct fb_info *fb) 158{ 159 uint32_t color; 160 161 if (regno >= 16) 162 return -EINVAL; 163 164 color = jzfb_convert_color_to_hw(red, &fb->var.red); 165 color |= jzfb_convert_color_to_hw(green, &fb->var.green); 166 color |= jzfb_convert_color_to_hw(blue, &fb->var.blue); 167 color |= jzfb_convert_color_to_hw(transp, &fb->var.transp); 168 169 ((uint32_t *)(fb->pseudo_palette))[regno] = color; 170 171 return 0; 172} 173 174static int jzfb_get_controller_bpp(struct jzfb *jzfb) 175{ 176 switch (jzfb->pdata->bpp) { 177 case 18: 178 case 24: 179 return 32; 180 case 15: 181 return 16; 182 default: 183 return jzfb->pdata->bpp; 184 } 185} 186 187static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb, 188 struct fb_var_screeninfo *var) 189{ 190 size_t i; 191 struct fb_videomode *mode = jzfb->pdata->modes; 192 193 for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { 194 if (mode->xres == var->xres && mode->yres == var->yres) 195 return mode; 196 } 197 198 return NULL; 199} 200 201static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) 202{ 203 struct jzfb *jzfb = fb->par; 204 struct fb_videomode *mode; 205 206 if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) && 207 var->bits_per_pixel != jzfb->pdata->bpp) 208 return -EINVAL; 209 210 mode = jzfb_get_mode(jzfb, var); 211 if (mode == NULL) 212 return -EINVAL; 213 214 fb_videomode_to_var(var, mode); 215 216 switch (jzfb->pdata->bpp) { 217 case 8: 218 break; 219 case 15: 220 var->red.offset = 10; 221 var->red.length = 5; 222 var->green.offset = 6; 223 var->green.length = 5; 224 var->blue.offset = 0; 225 var->blue.length = 5; 226 break; 227 case 16: 228 var->red.offset = 11; 229 var->red.length = 5; 230 var->green.offset = 5; 231 var->green.length = 6; 232 var->blue.offset = 0; 233 var->blue.length = 5; 234 break; 235 case 18: 236 var->red.offset = 16; 237 var->red.length = 6; 238 var->green.offset = 8; 239 var->green.length = 6; 240 var->blue.offset = 0; 241 var->blue.length = 6; 242 var->bits_per_pixel = 32; 243 break; 244 case 32: 245 case 24: 246 var->transp.offset = 24; 247 var->transp.length = 8; 248 var->red.offset = 16; 249 var->red.length = 8; 250 var->green.offset = 8; 251 var->green.length = 8; 252 var->blue.offset = 0; 253 var->blue.length = 8; 254 var->bits_per_pixel = 32; 255 break; 256 default: 257 break; 258 } 259 260 return 0; 261} 262 263static int jzfb_set_par(struct fb_info *info) 264{ 265 struct jzfb *jzfb = info->par; 266 struct jz4740_fb_platform_data *pdata = jzfb->pdata; 267 struct fb_var_screeninfo *var = &info->var; 268 struct fb_videomode *mode; 269 uint16_t hds, vds; 270 uint16_t hde, vde; 271 uint16_t ht, vt; 272 uint32_t ctrl; 273 uint32_t cfg; 274 unsigned long rate; 275 276 mode = jzfb_get_mode(jzfb, var); 277 if (mode == NULL) 278 return -EINVAL; 279 280 if (mode == info->mode) 281 return 0; 282 283 info->mode = mode; 284 285 hds = mode->hsync_len + mode->left_margin; 286 hde = hds + mode->xres; 287 ht = hde + mode->right_margin; 288 289 vds = mode->vsync_len + mode->upper_margin; 290 vde = vds + mode->yres; 291 vt = vde + mode->lower_margin; 292 293 ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16; 294 295 switch (pdata->bpp) { 296 case 1: 297 ctrl |= JZ_LCD_CTRL_BPP_1; 298 break; 299 case 2: 300 ctrl |= JZ_LCD_CTRL_BPP_2; 301 break; 302 case 4: 303 ctrl |= JZ_LCD_CTRL_BPP_4; 304 break; 305 case 8: 306 ctrl |= JZ_LCD_CTRL_BPP_8; 307 break; 308 case 15: 309 ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */ 310 case 16: 311 ctrl |= JZ_LCD_CTRL_BPP_15_16; 312 break; 313 case 18: 314 case 24: 315 case 32: 316 ctrl |= JZ_LCD_CTRL_BPP_18_24; 317 break; 318 default: 319 break; 320 } 321 322 cfg = pdata->lcd_type & 0xf; 323 324 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) 325 cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; 326 327 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) 328 cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW; 329 330 if (pdata->pixclk_falling_edge) 331 cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE; 332 333 if (pdata->date_enable_active_low) 334 cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW; 335 336 if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT) 337 cfg |= JZ_LCD_CFG_18_BIT; 338 339 if (mode->pixclock) { 340 rate = PICOS2KHZ(mode->pixclock) * 1000; 341 mode->refresh = rate / vt / ht; 342 } else { 343 if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL) 344 rate = mode->refresh * (vt + 2 * mode->xres) * ht; 345 else 346 rate = mode->refresh * vt * ht; 347 348 mode->pixclock = KHZ2PICOS(rate / 1000); 349 } 350 351 mutex_lock(&jzfb->lock); 352 if (!jzfb->is_enabled) 353 clk_enable(jzfb->ldclk); 354 else 355 ctrl |= JZ_LCD_CTRL_ENABLE; 356 357 switch (pdata->lcd_type) { 358 case JZ_LCD_TYPE_SPECIAL_TFT_1: 359 case JZ_LCD_TYPE_SPECIAL_TFT_2: 360 case JZ_LCD_TYPE_SPECIAL_TFT_3: 361 writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL); 362 writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS); 363 writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS); 364 writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV); 365 break; 366 default: 367 cfg |= JZ_LCD_CFG_PS_DISABLE; 368 cfg |= JZ_LCD_CFG_CLS_DISABLE; 369 cfg |= JZ_LCD_CFG_SPL_DISABLE; 370 cfg |= JZ_LCD_CFG_REV_DISABLE; 371 break; 372 } 373 374 writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC); 375 writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC); 376 377 writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT); 378 379 writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH); 380 writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV); 381 382 writel(cfg, jzfb->base + JZ_REG_LCD_CFG); 383 384 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); 385 386 if (!jzfb->is_enabled) 387 clk_disable_unprepare(jzfb->ldclk); 388 389 mutex_unlock(&jzfb->lock); 390 391 clk_set_rate(jzfb->lpclk, rate); 392 clk_set_rate(jzfb->ldclk, rate * 3); 393 394 return 0; 395} 396 397static void jzfb_enable(struct jzfb *jzfb) 398{ 399 uint32_t ctrl; 400 401 clk_prepare_enable(jzfb->ldclk); 402 403 pinctrl_pm_select_default_state(&jzfb->pdev->dev); 404 405 writel(0, jzfb->base + JZ_REG_LCD_STATE); 406 407 writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); 408 409 ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); 410 ctrl |= JZ_LCD_CTRL_ENABLE; 411 ctrl &= ~JZ_LCD_CTRL_DISABLE; 412 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); 413} 414 415static void jzfb_disable(struct jzfb *jzfb) 416{ 417 uint32_t ctrl; 418 419 ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL); 420 ctrl |= JZ_LCD_CTRL_DISABLE; 421 writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); 422 do { 423 ctrl = readl(jzfb->base + JZ_REG_LCD_STATE); 424 } while (!(ctrl & JZ_LCD_STATE_DISABLED)); 425 426 pinctrl_pm_select_sleep_state(&jzfb->pdev->dev); 427 428 clk_disable_unprepare(jzfb->ldclk); 429} 430 431static int jzfb_blank(int blank_mode, struct fb_info *info) 432{ 433 struct jzfb *jzfb = info->par; 434 435 switch (blank_mode) { 436 case FB_BLANK_UNBLANK: 437 mutex_lock(&jzfb->lock); 438 if (jzfb->is_enabled) { 439 mutex_unlock(&jzfb->lock); 440 return 0; 441 } 442 443 jzfb_enable(jzfb); 444 jzfb->is_enabled = 1; 445 446 mutex_unlock(&jzfb->lock); 447 break; 448 default: 449 mutex_lock(&jzfb->lock); 450 if (!jzfb->is_enabled) { 451 mutex_unlock(&jzfb->lock); 452 return 0; 453 } 454 455 jzfb_disable(jzfb); 456 jzfb->is_enabled = 0; 457 458 mutex_unlock(&jzfb->lock); 459 break; 460 } 461 462 return 0; 463} 464 465static int jzfb_alloc_devmem(struct jzfb *jzfb) 466{ 467 int max_videosize = 0; 468 struct fb_videomode *mode = jzfb->pdata->modes; 469 void *page; 470 int i; 471 472 for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { 473 if (max_videosize < mode->xres * mode->yres) 474 max_videosize = mode->xres * mode->yres; 475 } 476 477 max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3; 478 479 jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev, 480 sizeof(*jzfb->framedesc), 481 &jzfb->framedesc_phys, GFP_KERNEL); 482 483 if (!jzfb->framedesc) 484 return -ENOMEM; 485 486 jzfb->vidmem_size = PAGE_ALIGN(max_videosize); 487 jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev, 488 jzfb->vidmem_size, 489 &jzfb->vidmem_phys, GFP_KERNEL); 490 491 if (!jzfb->vidmem) 492 goto err_free_framedesc; 493 494 for (page = jzfb->vidmem; 495 page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); 496 page += PAGE_SIZE) { 497 SetPageReserved(virt_to_page(page)); 498 } 499 500 jzfb->framedesc->next = jzfb->framedesc_phys; 501 jzfb->framedesc->addr = jzfb->vidmem_phys; 502 jzfb->framedesc->id = 0xdeafbead; 503 jzfb->framedesc->cmd = 0; 504 jzfb->framedesc->cmd |= max_videosize / 4; 505 506 return 0; 507 508err_free_framedesc: 509 dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), 510 jzfb->framedesc, jzfb->framedesc_phys); 511 return -ENOMEM; 512} 513 514static void jzfb_free_devmem(struct jzfb *jzfb) 515{ 516 dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size, 517 jzfb->vidmem, jzfb->vidmem_phys); 518 dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc), 519 jzfb->framedesc, jzfb->framedesc_phys); 520} 521 522static struct fb_ops jzfb_ops = { 523 .owner = THIS_MODULE, 524 .fb_check_var = jzfb_check_var, 525 .fb_set_par = jzfb_set_par, 526 .fb_blank = jzfb_blank, 527 .fb_fillrect = sys_fillrect, 528 .fb_copyarea = sys_copyarea, 529 .fb_imageblit = sys_imageblit, 530 .fb_setcolreg = jzfb_setcolreg, 531}; 532 533static int jzfb_probe(struct platform_device *pdev) 534{ 535 int ret; 536 struct jzfb *jzfb; 537 struct fb_info *fb; 538 struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; 539 struct resource *mem; 540 541 if (!pdata) { 542 dev_err(&pdev->dev, "Missing platform data\n"); 543 return -ENXIO; 544 } 545 546 fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); 547 if (!fb) { 548 dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); 549 return -ENOMEM; 550 } 551 552 fb->fbops = &jzfb_ops; 553 fb->flags = FBINFO_DEFAULT; 554 555 jzfb = fb->par; 556 jzfb->pdev = pdev; 557 jzfb->pdata = pdata; 558 559 jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd"); 560 if (IS_ERR(jzfb->ldclk)) { 561 ret = PTR_ERR(jzfb->ldclk); 562 dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); 563 goto err_framebuffer_release; 564 } 565 566 jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk"); 567 if (IS_ERR(jzfb->lpclk)) { 568 ret = PTR_ERR(jzfb->lpclk); 569 dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); 570 goto err_framebuffer_release; 571 } 572 573 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 574 jzfb->base = devm_ioremap_resource(&pdev->dev, mem); 575 if (IS_ERR(jzfb->base)) { 576 ret = PTR_ERR(jzfb->base); 577 goto err_framebuffer_release; 578 } 579 580 platform_set_drvdata(pdev, jzfb); 581 582 mutex_init(&jzfb->lock); 583 584 fb_videomode_to_modelist(pdata->modes, pdata->num_modes, 585 &fb->modelist); 586 fb_videomode_to_var(&fb->var, pdata->modes); 587 fb->var.bits_per_pixel = pdata->bpp; 588 jzfb_check_var(&fb->var, fb); 589 590 ret = jzfb_alloc_devmem(jzfb); 591 if (ret) { 592 dev_err(&pdev->dev, "Failed to allocate video memory\n"); 593 goto err_framebuffer_release; 594 } 595 596 fb->fix = jzfb_fix; 597 fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; 598 fb->fix.mmio_start = mem->start; 599 fb->fix.mmio_len = resource_size(mem); 600 fb->fix.smem_start = jzfb->vidmem_phys; 601 fb->fix.smem_len = fb->fix.line_length * fb->var.yres; 602 fb->screen_base = jzfb->vidmem; 603 fb->pseudo_palette = jzfb->pseudo_palette; 604 605 fb_alloc_cmap(&fb->cmap, 256, 0); 606 607 clk_prepare_enable(jzfb->ldclk); 608 jzfb->is_enabled = 1; 609 610 writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); 611 612 fb->mode = NULL; 613 jzfb_set_par(fb); 614 615 ret = register_framebuffer(fb); 616 if (ret) { 617 dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); 618 goto err_free_devmem; 619 } 620 621 jzfb->fb = fb; 622 623 return 0; 624 625err_free_devmem: 626 fb_dealloc_cmap(&fb->cmap); 627 jzfb_free_devmem(jzfb); 628err_framebuffer_release: 629 framebuffer_release(fb); 630 return ret; 631} 632 633static int jzfb_remove(struct platform_device *pdev) 634{ 635 struct jzfb *jzfb = platform_get_drvdata(pdev); 636 637 jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb); 638 639 fb_dealloc_cmap(&jzfb->fb->cmap); 640 jzfb_free_devmem(jzfb); 641 642 framebuffer_release(jzfb->fb); 643 644 return 0; 645} 646 647#ifdef CONFIG_PM 648 649static int jzfb_suspend(struct device *dev) 650{ 651 struct jzfb *jzfb = dev_get_drvdata(dev); 652 653 console_lock(); 654 fb_set_suspend(jzfb->fb, 1); 655 console_unlock(); 656 657 mutex_lock(&jzfb->lock); 658 if (jzfb->is_enabled) 659 jzfb_disable(jzfb); 660 mutex_unlock(&jzfb->lock); 661 662 return 0; 663} 664 665static int jzfb_resume(struct device *dev) 666{ 667 struct jzfb *jzfb = dev_get_drvdata(dev); 668 clk_prepare_enable(jzfb->ldclk); 669 670 mutex_lock(&jzfb->lock); 671 if (jzfb->is_enabled) 672 jzfb_enable(jzfb); 673 mutex_unlock(&jzfb->lock); 674 675 console_lock(); 676 fb_set_suspend(jzfb->fb, 0); 677 console_unlock(); 678 679 return 0; 680} 681 682static const struct dev_pm_ops jzfb_pm_ops = { 683 .suspend = jzfb_suspend, 684 .resume = jzfb_resume, 685 .poweroff = jzfb_suspend, 686 .restore = jzfb_resume, 687}; 688 689#define JZFB_PM_OPS (&jzfb_pm_ops) 690 691#else 692#define JZFB_PM_OPS NULL 693#endif 694 695static struct platform_driver jzfb_driver = { 696 .probe = jzfb_probe, 697 .remove = jzfb_remove, 698 .driver = { 699 .name = "jz4740-fb", 700 .pm = JZFB_PM_OPS, 701 }, 702}; 703module_platform_driver(jzfb_driver); 704 705MODULE_LICENSE("GPL"); 706MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 707MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver"); 708MODULE_ALIAS("platform:jz4740-fb");