aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/da8xx-fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/da8xx-fb.c')
-rw-r--r--drivers/video/da8xx-fb.c176
1 files changed, 155 insertions, 21 deletions
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index ea1fd3f47511..8d244ba0f601 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -28,6 +28,9 @@
28#include <linux/uaccess.h> 28#include <linux/uaccess.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/clk.h> 30#include <linux/clk.h>
31#include <linux/cpufreq.h>
32#include <linux/console.h>
33#include <linux/slab.h>
31#include <video/da8xx-fb.h> 34#include <video/da8xx-fb.h>
32 35
33#define DRIVER_NAME "da8xx_lcdc" 36#define DRIVER_NAME "da8xx_lcdc"
@@ -113,6 +116,12 @@ struct da8xx_fb_par {
113 unsigned short pseudo_palette[16]; 116 unsigned short pseudo_palette[16];
114 unsigned int databuf_sz; 117 unsigned int databuf_sz;
115 unsigned int palette_sz; 118 unsigned int palette_sz;
119 unsigned int pxl_clk;
120 int blank;
121#ifdef CONFIG_CPU_FREQ
122 struct notifier_block freq_transition;
123#endif
124 void (*panel_power_ctrl)(int);
116}; 125};
117 126
118/* Variable Screen Information */ 127/* Variable Screen Information */
@@ -155,7 +164,7 @@ struct da8xx_panel {
155 int vfp; /* Vertical front porch */ 164 int vfp; /* Vertical front porch */
156 int vbp; /* Vertical back porch */ 165 int vbp; /* Vertical back porch */
157 int vsw; /* Vertical Sync Pulse Width */ 166 int vsw; /* Vertical Sync Pulse Width */
158 int pxl_clk; /* Pixel clock */ 167 unsigned int pxl_clk; /* Pixel clock */
159 unsigned char invert_pxl_clk; /* Invert Pixel clock */ 168 unsigned char invert_pxl_clk; /* Invert Pixel clock */
160}; 169};
161 170
@@ -171,7 +180,7 @@ static struct da8xx_panel known_lcd_panels[] = {
171 .vfp = 2, 180 .vfp = 2,
172 .vbp = 2, 181 .vbp = 2,
173 .vsw = 0, 182 .vsw = 0,
174 .pxl_clk = 0x10, 183 .pxl_clk = 4608000,
175 .invert_pxl_clk = 1, 184 .invert_pxl_clk = 1,
176 }, 185 },
177 /* Sharp LK043T1DG01 */ 186 /* Sharp LK043T1DG01 */
@@ -185,13 +194,23 @@ static struct da8xx_panel known_lcd_panels[] = {
185 .vfp = 2, 194 .vfp = 2,
186 .vbp = 2, 195 .vbp = 2,
187 .vsw = 10, 196 .vsw = 10,
188 .pxl_clk = 0x12, 197 .pxl_clk = 7833600,
189 .invert_pxl_clk = 0, 198 .invert_pxl_clk = 0,
190 }, 199 },
191}; 200};
192 201
202/* Enable the Raster Engine of the LCD Controller */
203static inline void lcd_enable_raster(void)
204{
205 u32 reg;
206
207 reg = lcdc_read(LCD_RASTER_CTRL_REG);
208 if (!(reg & LCD_RASTER_ENABLE))
209 lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
210}
211
193/* Disable the Raster Engine of the LCD Controller */ 212/* Disable the Raster Engine of the LCD Controller */
194static void lcd_disable_raster(struct da8xx_fb_par *par) 213static inline void lcd_disable_raster(void)
195{ 214{
196 u32 reg; 215 u32 reg;
197 216
@@ -443,14 +462,25 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
443static void lcd_reset(struct da8xx_fb_par *par) 462static void lcd_reset(struct da8xx_fb_par *par)
444{ 463{
445 /* Disable the Raster if previously Enabled */ 464 /* Disable the Raster if previously Enabled */
446 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) 465 lcd_disable_raster();
447 lcd_disable_raster(par);
448 466
449 /* DMA has to be disabled */ 467 /* DMA has to be disabled */
450 lcdc_write(0, LCD_DMA_CTRL_REG); 468 lcdc_write(0, LCD_DMA_CTRL_REG);
451 lcdc_write(0, LCD_RASTER_CTRL_REG); 469 lcdc_write(0, LCD_RASTER_CTRL_REG);
452} 470}
453 471
472static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
473{
474 unsigned int lcd_clk, div;
475
476 lcd_clk = clk_get_rate(par->lcdc_clk);
477 div = lcd_clk / par->pxl_clk;
478
479 /* Configure the LCD clock divisor. */
480 lcdc_write(LCD_CLK_DIVISOR(div) |
481 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
482}
483
454static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, 484static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
455 struct da8xx_panel *panel) 485 struct da8xx_panel *panel)
456{ 486{
@@ -459,9 +489,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
459 489
460 lcd_reset(par); 490 lcd_reset(par);
461 491
462 /* Configure the LCD clock divisor. */ 492 /* Calculate the divider */
463 lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | 493 lcd_calc_clk_divider(par);
464 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
465 494
466 if (panel->invert_pxl_clk) 495 if (panel->invert_pxl_clk)
467 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | 496 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |
@@ -513,13 +542,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
513static irqreturn_t lcdc_irq_handler(int irq, void *arg) 542static irqreturn_t lcdc_irq_handler(int irq, void *arg)
514{ 543{
515 u32 stat = lcdc_read(LCD_STAT_REG); 544 u32 stat = lcdc_read(LCD_STAT_REG);
516 u32 reg;
517 545
518 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { 546 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
519 reg = lcdc_read(LCD_RASTER_CTRL_REG); 547 lcd_disable_raster();
520 lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
521 lcdc_write(stat, LCD_STAT_REG); 548 lcdc_write(stat, LCD_STAT_REG);
522 lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); 549 lcd_enable_raster();
523 } else 550 } else
524 lcdc_write(stat, LCD_STAT_REG); 551 lcdc_write(stat, LCD_STAT_REG);
525 552
@@ -574,6 +601,38 @@ static int fb_check_var(struct fb_var_screeninfo *var,
574 return err; 601 return err;
575} 602}
576 603
604#ifdef CONFIG_CPU_FREQ
605static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
606 unsigned long val, void *data)
607{
608 struct da8xx_fb_par *par;
609
610 par = container_of(nb, struct da8xx_fb_par, freq_transition);
611 if (val == CPUFREQ_PRECHANGE) {
612 lcd_disable_raster();
613 } else if (val == CPUFREQ_POSTCHANGE) {
614 lcd_calc_clk_divider(par);
615 lcd_enable_raster();
616 }
617
618 return 0;
619}
620
621static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par)
622{
623 par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition;
624
625 return cpufreq_register_notifier(&par->freq_transition,
626 CPUFREQ_TRANSITION_NOTIFIER);
627}
628
629static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
630{
631 cpufreq_unregister_notifier(&par->freq_transition,
632 CPUFREQ_TRANSITION_NOTIFIER);
633}
634#endif
635
577static int __devexit fb_remove(struct platform_device *dev) 636static int __devexit fb_remove(struct platform_device *dev)
578{ 637{
579 struct fb_info *info = dev_get_drvdata(&dev->dev); 638 struct fb_info *info = dev_get_drvdata(&dev->dev);
@@ -581,8 +640,13 @@ static int __devexit fb_remove(struct platform_device *dev)
581 if (info) { 640 if (info) {
582 struct da8xx_fb_par *par = info->par; 641 struct da8xx_fb_par *par = info->par;
583 642
584 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) 643#ifdef CONFIG_CPU_FREQ
585 lcd_disable_raster(par); 644 lcd_da8xx_cpufreq_deregister(par);
645#endif
646 if (par->panel_power_ctrl)
647 par->panel_power_ctrl(0);
648
649 lcd_disable_raster();
586 lcdc_write(0, LCD_RASTER_CTRL_REG); 650 lcdc_write(0, LCD_RASTER_CTRL_REG);
587 651
588 /* disable DMA */ 652 /* disable DMA */
@@ -639,6 +703,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
639 return 0; 703 return 0;
640} 704}
641 705
706static int cfb_blank(int blank, struct fb_info *info)
707{
708 struct da8xx_fb_par *par = info->par;
709 int ret = 0;
710
711 if (par->blank == blank)
712 return 0;
713
714 par->blank = blank;
715 switch (blank) {
716 case FB_BLANK_UNBLANK:
717 if (par->panel_power_ctrl)
718 par->panel_power_ctrl(1);
719
720 lcd_enable_raster();
721 break;
722 case FB_BLANK_POWERDOWN:
723 if (par->panel_power_ctrl)
724 par->panel_power_ctrl(0);
725
726 lcd_disable_raster();
727 break;
728 default:
729 ret = -EINVAL;
730 }
731
732 return ret;
733}
734
642static struct fb_ops da8xx_fb_ops = { 735static struct fb_ops da8xx_fb_ops = {
643 .owner = THIS_MODULE, 736 .owner = THIS_MODULE,
644 .fb_check_var = fb_check_var, 737 .fb_check_var = fb_check_var,
@@ -647,6 +740,7 @@ static struct fb_ops da8xx_fb_ops = {
647 .fb_fillrect = cfb_fillrect, 740 .fb_fillrect = cfb_fillrect,
648 .fb_copyarea = cfb_copyarea, 741 .fb_copyarea = cfb_copyarea,
649 .fb_imageblit = cfb_imageblit, 742 .fb_imageblit = cfb_imageblit,
743 .fb_blank = cfb_blank,
650}; 744};
651 745
652static int __init fb_probe(struct platform_device *device) 746static int __init fb_probe(struct platform_device *device)
@@ -721,6 +815,12 @@ static int __init fb_probe(struct platform_device *device)
721 } 815 }
722 816
723 par = da8xx_fb_info->par; 817 par = da8xx_fb_info->par;
818 par->lcdc_clk = fb_clk;
819 par->pxl_clk = lcdc_info->pxl_clk;
820 if (fb_pdata->panel_power_ctrl) {
821 par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
822 par->panel_power_ctrl(1);
823 }
724 824
725 if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { 825 if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {
726 dev_err(&device->dev, "lcd_init failed\n"); 826 dev_err(&device->dev, "lcd_init failed\n");
@@ -754,8 +854,6 @@ static int __init fb_probe(struct platform_device *device)
754 da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; 854 da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
755 da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; 855 da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
756 856
757 par->lcdc_clk = fb_clk;
758
759 par->irq = platform_get_irq(device, 0); 857 par->irq = platform_get_irq(device, 0);
760 if (par->irq < 0) { 858 if (par->irq < 0) {
761 ret = -ENOENT; 859 ret = -ENOENT;
@@ -814,12 +912,24 @@ static int __init fb_probe(struct platform_device *device)
814 goto err_dealloc_cmap; 912 goto err_dealloc_cmap;
815 } 913 }
816 914
915#ifdef CONFIG_CPU_FREQ
916 ret = lcd_da8xx_cpufreq_register(par);
917 if (ret) {
918 dev_err(&device->dev, "failed to register cpufreq\n");
919 goto err_cpu_freq;
920 }
921#endif
922
817 /* enable raster engine */ 923 /* enable raster engine */
818 lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | 924 lcd_enable_raster();
819 LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
820 925
821 return 0; 926 return 0;
822 927
928#ifdef CONFIG_CPU_FREQ
929err_cpu_freq:
930 unregister_framebuffer(da8xx_fb_info);
931#endif
932
823err_dealloc_cmap: 933err_dealloc_cmap:
824 fb_dealloc_cmap(&da8xx_fb_info->cmap); 934 fb_dealloc_cmap(&da8xx_fb_info->cmap);
825 935
@@ -852,11 +962,35 @@ err_request_mem:
852#ifdef CONFIG_PM 962#ifdef CONFIG_PM
853static int fb_suspend(struct platform_device *dev, pm_message_t state) 963static int fb_suspend(struct platform_device *dev, pm_message_t state)
854{ 964{
855 return -EBUSY; 965 struct fb_info *info = platform_get_drvdata(dev);
966 struct da8xx_fb_par *par = info->par;
967
968 acquire_console_sem();
969 if (par->panel_power_ctrl)
970 par->panel_power_ctrl(0);
971
972 fb_set_suspend(info, 1);
973 lcd_disable_raster();
974 clk_disable(par->lcdc_clk);
975 release_console_sem();
976
977 return 0;
856} 978}
857static int fb_resume(struct platform_device *dev) 979static int fb_resume(struct platform_device *dev)
858{ 980{
859 return -EBUSY; 981 struct fb_info *info = platform_get_drvdata(dev);
982 struct da8xx_fb_par *par = info->par;
983
984 acquire_console_sem();
985 if (par->panel_power_ctrl)
986 par->panel_power_ctrl(1);
987
988 clk_enable(par->lcdc_clk);
989 lcd_enable_raster();
990 fb_set_suspend(info, 0);
991 release_console_sem();
992
993 return 0;
860} 994}
861#else 995#else
862#define fb_suspend NULL 996#define fb_suspend NULL