fbdev: move FBIO_WAITFORVSYNC to linux/fb.h
[safe/jmp/linux-2.6] / drivers / video / s3c2410fb.c
index 24d5ea5..2b094de 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/div64.h>
 
 #include <asm/mach/map.h>
-#include <asm/arch/regs-lcd.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/fb.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-gpio.h>
+#include <mach/fb.h>
 
 #ifdef CONFIG_PM
 #include <linux/pm.h>
@@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info)
 static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
                                          unsigned long pixclk)
 {
-       unsigned long clk = clk_get_rate(fbi->clk);
+       unsigned long clk = fbi->clk_rate;
        unsigned long long div;
 
        /* pixclk is in picoseconds, our clock is in Hz
@@ -368,7 +369,9 @@ static void s3c2410fb_activate_var(struct fb_info *info)
        void __iomem *regs = fbi->io;
        int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
        struct fb_var_screeninfo *var = &info->var;
-       int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;
+       int clkdiv;
+
+       clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);
 
        dprintk("%s: var->xres  = %d\n", __func__, var->xres);
        dprintk("%s: var->yres  = %d\n", __func__, var->yres);
@@ -758,6 +761,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
+                                       unsigned long val, void *data)
+{
+       struct cpufreq_freqs *freqs = data;
+       struct s3c2410fb_info *info;
+       struct fb_info *fbinfo;
+       long delta_f;
+
+       info = container_of(nb, struct s3c2410fb_info, freq_transition);
+       fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+
+       /* work out change, <0 for speed-up */
+       delta_f = info->clk_rate - clk_get_rate(info->clk);
+
+       if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
+           (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
+               info->clk_rate = clk_get_rate(info->clk);
+               s3c2410fb_activate_var(fbinfo);
+       }
+
+       return 0;
+}
+
+static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
+{
+       info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
+
+       return cpufreq_register_notifier(&info->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
+{
+       cpufreq_unregister_notifier(&info->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
+{
+       return 0;
+}
+
+static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
+{
+}
+#endif
+
+
 static char driver_name[] = "s3c2410fb";
 
 static int __init s3c24xxfb_probe(struct platform_device *pdev,
@@ -875,6 +929,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        msleep(1);
 
+       info->clk_rate = clk_get_rate(info->clk);
+
        /* find maximum required memory size for display */
        for (i = 0; i < mach_info->num_displays; i++) {
                unsigned long smem_len = mach_info->displays[i].xres;
@@ -904,11 +960,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        s3c2410fb_check_var(&fbinfo->var, fbinfo);
 
+       ret = s3c2410fb_cpufreq_register(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register cpufreq\n");
+               goto free_video_memory;
+       }
+
        ret = register_framebuffer(fbinfo);
        if (ret < 0) {
                printk(KERN_ERR "Failed to register framebuffer device: %d\n",
                        ret);
-               goto free_video_memory;
+               goto free_cpufreq;
        }
 
        /* create device files */
@@ -922,6 +984,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        return 0;
 
+ free_cpufreq:
+       s3c2410fb_cpufreq_deregister(info);
 free_video_memory:
        s3c2410fb_unmap_video_memory(fbinfo);
 release_clock:
@@ -940,12 +1004,12 @@ dealloc_fb:
        return ret;
 }
 
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __devinit s3c2410fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2410);
 }
 
-static int __init s3c2412fb_probe(struct platform_device *pdev)
+static int __devinit s3c2412fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2412);
 }
@@ -961,6 +1025,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
        int irq;
 
        unregister_framebuffer(fbinfo);
+       s3c2410fb_cpufreq_deregister(info);
 
        s3c2410fb_lcd_enable(info, 0);
        msleep(1);
@@ -1017,6 +1082,10 @@ static int s3c2410fb_resume(struct platform_device *dev)
 
        s3c2410fb_init_registers(fbinfo);
 
+       /* re-activate our display after resume */
+       s3c2410fb_activate_var(fbinfo);
+       s3c2410fb_blank(FB_BLANK_UNBLANK, fbinfo);
+
        return 0;
 }
 
@@ -1052,7 +1121,7 @@ int __init s3c2410fb_init(void)
        int ret = platform_driver_register(&s3c2410fb_driver);
 
        if (ret == 0)
-               ret = platform_driver_register(&s3c2412fb_driver);;
+               ret = platform_driver_register(&s3c2412fb_driver);
 
        return ret;
 }
@@ -1070,3 +1139,5 @@ MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
              "Ben Dooks <ben-linux@fluff.org>");
 MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2410-lcd");
+MODULE_ALIAS("platform:s3c2412-lcd");