diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 19:50:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 19:50:13 -0700 |
commit | 517d08699b250021303f9a7cf0d758b6dc0748ed (patch) | |
tree | 5e5b0134c3fffb78fe9d8b1641a64ff28fdd7bbc /drivers/video/s3c2410fb.c | |
parent | 8eeee4e2f04fc551f50c9d9847da2d73d7d33728 (diff) | |
parent | a34601c5d84134055782ee031d58d82f5440e918 (diff) |
Merge branch 'akpm'
* akpm: (182 commits)
fbdev: bf54x-lq043fb: use kzalloc over kmalloc/memset
fbdev: *bfin*: fix __dev{init,exit} markings
fbdev: *bfin*: drop unnecessary calls to memset
fbdev: bfin-t350mcqb-fb: drop unused local variables
fbdev: blackfin has __raw I/O accessors, so use them in fb.h
fbdev: s1d13xxxfb: add accelerated bitblt functions
tcx: use standard fields for framebuffer physical address and length
fbdev: add support for handoff from firmware to hw framebuffers
intelfb: fix a bug when changing video timing
fbdev: use framebuffer_release() for freeing fb_info structures
radeon: P2G2CLK_ALWAYS_ONb tested twice, should 2nd be P2G2CLK_DAC_ALWAYS_ONb?
s3c-fb: CPUFREQ frequency scaling support
s3c-fb: fix resource releasing on error during probing
carminefb: fix possible access beyond end of carmine_modedb[]
acornfb: remove fb_mmap function
mb862xxfb: use CONFIG_OF instead of CONFIG_PPC_OF
mb862xxfb: restrict compliation of platform driver to PPC
Samsung SoC Framebuffer driver: add Alpha Channel support
atmel-lcdc: fix pixclock upper bound detection
offb: use framebuffer_alloc() to allocate fb_info struct
...
Manually fix up conflicts due to kmemcheck in mm/slab.c
Diffstat (limited to 'drivers/video/s3c2410fb.c')
-rw-r--r-- | drivers/video/s3c2410fb.c | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index b0b4513ba53..7da0027e240 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -24,6 +24,7 @@ #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> @@ -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 @@ -758,6 +759,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 +927,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 +958,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 +982,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: @@ -961,6 +1023,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); |