diff options
Diffstat (limited to 'drivers/video/imxfb.c')
-rw-r--r-- | drivers/video/imxfb.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index bd1cb75cd14b..8f7a2b2c78e7 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -26,9 +26,11 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
28 | #include <linux/cpufreq.h> | 28 | #include <linux/cpufreq.h> |
29 | #include <linux/clk.h> | ||
29 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
30 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
31 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/math64.h> | ||
32 | 34 | ||
33 | #include <mach/imxfb.h> | 35 | #include <mach/imxfb.h> |
34 | 36 | ||
@@ -141,6 +143,7 @@ struct imxfb_rgb { | |||
141 | struct imxfb_info { | 143 | struct imxfb_info { |
142 | struct platform_device *pdev; | 144 | struct platform_device *pdev; |
143 | void __iomem *regs; | 145 | void __iomem *regs; |
146 | struct clk *clk; | ||
144 | 147 | ||
145 | u_int max_bpp; | 148 | u_int max_bpp; |
146 | u_int max_xres; | 149 | u_int max_xres; |
@@ -403,6 +406,8 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) | |||
403 | 406 | ||
404 | writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); | 407 | writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR); |
405 | 408 | ||
409 | clk_enable(fbi->clk); | ||
410 | |||
406 | if (fbi->backlight_power) | 411 | if (fbi->backlight_power) |
407 | fbi->backlight_power(1); | 412 | fbi->backlight_power(1); |
408 | if (fbi->lcd_power) | 413 | if (fbi->lcd_power) |
@@ -418,6 +423,8 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) | |||
418 | if (fbi->lcd_power) | 423 | if (fbi->lcd_power) |
419 | fbi->lcd_power(0); | 424 | fbi->lcd_power(0); |
420 | 425 | ||
426 | clk_disable(fbi->clk); | ||
427 | |||
421 | writel(0, fbi->regs + LCDC_RMCR); | 428 | writel(0, fbi->regs + LCDC_RMCR); |
422 | } | 429 | } |
423 | 430 | ||
@@ -461,6 +468,9 @@ static struct fb_ops imxfb_ops = { | |||
461 | static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) | 468 | static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) |
462 | { | 469 | { |
463 | struct imxfb_info *fbi = info->par; | 470 | struct imxfb_info *fbi = info->par; |
471 | unsigned int pcr, lcd_clk; | ||
472 | unsigned long long tmp; | ||
473 | |||
464 | pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", | 474 | pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", |
465 | var->xres, var->hsync_len, | 475 | var->xres, var->hsync_len, |
466 | var->left_margin, var->right_margin); | 476 | var->left_margin, var->right_margin); |
@@ -507,7 +517,23 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
507 | 517 | ||
508 | writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), | 518 | writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), |
509 | fbi->regs + LCDC_SIZE); | 519 | fbi->regs + LCDC_SIZE); |
510 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 520 | |
521 | lcd_clk = clk_get_rate(fbi->clk); | ||
522 | tmp = var->pixclock * (unsigned long long)lcd_clk; | ||
523 | do_div(tmp, 1000000); | ||
524 | if (do_div(tmp, 1000000) > 500000) | ||
525 | tmp++; | ||
526 | pcr = (unsigned int)tmp; | ||
527 | if (--pcr > 0x3F) { | ||
528 | pcr = 0x3F; | ||
529 | printk(KERN_WARNING "Must limit pixel clock to %uHz\n", | ||
530 | lcd_clk / pcr); | ||
531 | } | ||
532 | |||
533 | /* add sync polarities */ | ||
534 | pcr |= fbi->pcr & ~0x3F; | ||
535 | |||
536 | writel(pcr, fbi->regs + LCDC_PCR); | ||
511 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 537 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); |
512 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 538 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); |
513 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 539 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); |
@@ -649,6 +675,13 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
649 | goto failed_req; | 675 | goto failed_req; |
650 | } | 676 | } |
651 | 677 | ||
678 | fbi->clk = clk_get(&pdev->dev, NULL); | ||
679 | if (IS_ERR(fbi->clk)) { | ||
680 | ret = PTR_ERR(fbi->clk);; | ||
681 | dev_err(&pdev->dev, "unable to get clock: %d\n", ret); | ||
682 | goto failed_getclock; | ||
683 | } | ||
684 | |||
652 | fbi->regs = ioremap(res->start, resource_size(res)); | 685 | fbi->regs = ioremap(res->start, resource_size(res)); |
653 | if (fbi->regs == NULL) { | 686 | if (fbi->regs == NULL) { |
654 | printk(KERN_ERR"Cannot map frame buffer registers\n"); | 687 | printk(KERN_ERR"Cannot map frame buffer registers\n"); |
@@ -717,6 +750,8 @@ failed_platform_init: | |||
717 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, | 750 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, |
718 | fbi->map_dma); | 751 | fbi->map_dma); |
719 | failed_map: | 752 | failed_map: |
753 | clk_put(fbi->clk); | ||
754 | failed_getclock: | ||
720 | iounmap(fbi->regs); | 755 | iounmap(fbi->regs); |
721 | failed_ioremap: | 756 | failed_ioremap: |
722 | release_mem_region(res->start, res->end - res->start); | 757 | release_mem_region(res->start, res->end - res->start); |
@@ -751,6 +786,9 @@ static int __devexit imxfb_remove(struct platform_device *pdev) | |||
751 | 786 | ||
752 | iounmap(fbi->regs); | 787 | iounmap(fbi->regs); |
753 | release_mem_region(res->start, res->end - res->start + 1); | 788 | release_mem_region(res->start, res->end - res->start + 1); |
789 | clk_disable(fbi->clk); | ||
790 | clk_put(fbi->clk); | ||
791 | |||
754 | platform_set_drvdata(pdev, NULL); | 792 | platform_set_drvdata(pdev, NULL); |
755 | 793 | ||
756 | return 0; | 794 | return 0; |