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