diff options
author | Ben Dooks <ben@simtec.co.uk> | 2009-06-16 18:34:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:59 -0400 |
commit | 0dac6ecdc056b83ac66e5b5c923fb73268f4332d (patch) | |
tree | 9d7841f2c5b1e7a49b485cfa670a9a3728a509c3 | |
parent | ddc518d9f88d7cf82bd974737ce977193785335d (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>
-rw-r--r-- | drivers/video/s3c2410fb.c | 67 | ||||
-rw-r--r-- | drivers/video/s3c2410fb.h | 5 |
2 files changed, 70 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) | |||
89 | static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, | 90 | static 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 | |||
764 | static 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 | |||
787 | static 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 | |||
795 | static 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 | ||
802 | static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info) | ||
803 | { | ||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) | ||
808 | { | ||
809 | } | ||
810 | #endif | ||
811 | |||
812 | |||
761 | static char driver_name[] = "s3c2410fb"; | 813 | static char driver_name[] = "s3c2410fb"; |
762 | 814 | ||
763 | static int __init s3c24xxfb_probe(struct platform_device *pdev, | 815 | static 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); | ||
925 | free_video_memory: | 987 | free_video_memory: |
926 | s3c2410fb_unmap_video_memory(fbinfo); | 988 | s3c2410fb_unmap_video_memory(fbinfo); |
927 | release_clock: | 989 | release_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); |
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 9a6ba3e9d1b8..47a17bd23011 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h | |||
@@ -29,8 +29,13 @@ struct s3c2410fb_info { | |||
29 | enum s3c_drv_type drv_type; | 29 | enum s3c_drv_type drv_type; |
30 | struct s3c2410fb_hw regs; | 30 | struct s3c2410fb_hw regs; |
31 | 31 | ||
32 | unsigned long clk_rate; | ||
32 | unsigned int palette_ready; | 33 | unsigned int palette_ready; |
33 | 34 | ||
35 | #ifdef CONFIG_CPU_FREQ | ||
36 | struct notifier_block freq_transition; | ||
37 | #endif | ||
38 | |||
34 | /* keep these registers in case we need to re-write palette */ | 39 | /* keep these registers in case we need to re-write palette */ |
35 | u32 palette_buffer[256]; | 40 | u32 palette_buffer[256]; |
36 | u32 pseudo_pal[16]; | 41 | u32 pseudo_pal[16]; |