aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/s3c2410fb.c
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-06-16 18:34:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:47:59 -0400
commit0dac6ecdc056b83ac66e5b5c923fb73268f4332d (patch)
tree9d7841f2c5b1e7a49b485cfa670a9a3728a509c3 /drivers/video/s3c2410fb.c
parentddc518d9f88d7cf82bd974737ce977193785335d (diff)
s3c-fb: CPUFREQ frequency scaling support
Add support for CPU frequency scaling in the S3C24XX video driver. Signed-off-by: Simtec Linux Team <linux@simtec.co.uk> Signed-off-by: Ben Dooks <ben@simtec.co.uk> Cc: Dave Jones <davej@codemonkey.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/s3c2410fb.c')
-rw-r--r--drivers/video/s3c2410fb.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index b0b4513ba537..7da0027e2409 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -24,6 +24,7 @@
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <linux/cpufreq.h>
27 28
28#include <asm/io.h> 29#include <asm/io.h>
29#include <asm/div64.h> 30#include <asm/div64.h>
@@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info)
89static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, 90static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
90 unsigned long pixclk) 91 unsigned long pixclk)
91{ 92{
92 unsigned long clk = clk_get_rate(fbi->clk); 93 unsigned long clk = fbi->clk_rate;
93 unsigned long long div; 94 unsigned long long div;
94 95
95 /* pixclk is in picoseconds, our clock is in Hz 96 /* pixclk is in picoseconds, our clock is in Hz
@@ -758,6 +759,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
758 return IRQ_HANDLED; 759 return IRQ_HANDLED;
759} 760}
760 761
762#ifdef CONFIG_CPU_FREQ
763
764static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
765 unsigned long val, void *data)
766{
767 struct cpufreq_freqs *freqs = data;
768 struct s3c2410fb_info *info;
769 struct fb_info *fbinfo;
770 long delta_f;
771
772 info = container_of(nb, struct s3c2410fb_info, freq_transition);
773 fbinfo = platform_get_drvdata(to_platform_device(info->dev));
774
775 /* work out change, <0 for speed-up */
776 delta_f = info->clk_rate - clk_get_rate(info->clk);
777
778 if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
779 (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
780 info->clk_rate = clk_get_rate(info->clk);
781 s3c2410fb_activate_var(fbinfo);
782 }
783
784 return 0;
785}
786
787static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
788{
789 info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
790
791 return cpufreq_register_notifier(&info->freq_transition,
792 CPUFREQ_TRANSITION_NOTIFIER);
793}
794
795static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
796{
797 cpufreq_unregister_notifier(&info->freq_transition,
798 CPUFREQ_TRANSITION_NOTIFIER);
799}
800
801#else
802static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
803{
804 return 0;
805}
806
807static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
808{
809}
810#endif
811
812
761static char driver_name[] = "s3c2410fb"; 813static char driver_name[] = "s3c2410fb";
762 814
763static int __init s3c24xxfb_probe(struct platform_device *pdev, 815static int __init s3c24xxfb_probe(struct platform_device *pdev,
@@ -875,6 +927,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
875 927
876 msleep(1); 928 msleep(1);
877 929
930 info->clk_rate = clk_get_rate(info->clk);
931
878 /* find maximum required memory size for display */ 932 /* find maximum required memory size for display */
879 for (i = 0; i < mach_info->num_displays; i++) { 933 for (i = 0; i < mach_info->num_displays; i++) {
880 unsigned long smem_len = mach_info->displays[i].xres; 934 unsigned long smem_len = mach_info->displays[i].xres;
@@ -904,11 +958,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
904 958
905 s3c2410fb_check_var(&fbinfo->var, fbinfo); 959 s3c2410fb_check_var(&fbinfo->var, fbinfo);
906 960
961 ret = s3c2410fb_cpufreq_register(info);
962 if (ret < 0) {
963 dev_err(&pdev->dev, "Failed to register cpufreq\n");
964 goto free_video_memory;
965 }
966
907 ret = register_framebuffer(fbinfo); 967 ret = register_framebuffer(fbinfo);
908 if (ret < 0) { 968 if (ret < 0) {
909 printk(KERN_ERR "Failed to register framebuffer device: %d\n", 969 printk(KERN_ERR "Failed to register framebuffer device: %d\n",
910 ret); 970 ret);
911 goto free_video_memory; 971 goto free_cpufreq;
912 } 972 }
913 973
914 /* create device files */ 974 /* create device files */
@@ -922,6 +982,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
922 982
923 return 0; 983 return 0;
924 984
985 free_cpufreq:
986 s3c2410fb_cpufreq_deregister(info);
925free_video_memory: 987free_video_memory:
926 s3c2410fb_unmap_video_memory(fbinfo); 988 s3c2410fb_unmap_video_memory(fbinfo);
927release_clock: 989release_clock:
@@ -961,6 +1023,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
961 int irq; 1023 int irq;
962 1024
963 unregister_framebuffer(fbinfo); 1025 unregister_framebuffer(fbinfo);
1026 s3c2410fb_cpufreq_deregister(info);
964 1027
965 s3c2410fb_lcd_enable(info, 0); 1028 s3c2410fb_lcd_enable(info, 0);
966 msleep(1); 1029 msleep(1);