From: Andrew M. <ak...@li...> - 2009-05-29 20:45:57
|
On Thu, 28 May 2009 22:04:30 +0100 Ben Dooks <be...@si...> wrote: > Add support for CPU frequency scaling in the S3C24XX video driver. > Looks nice and neat. Did you get to look at Krzysztof's s3c-fb-fix-resource-releasing-on-error-during-probing.patch, btw? Is it 2.6.30 material? > > --- > drivers/video/s3c2410fb.c | 67 ++++++++++++++++++++++++++++++++++++++++++++-- > drivers/video/s3c2410fb.h | 5 +++ > 2 files changed, 70 insertions(+), 2 deletions(-) > > Index: b/drivers/video/s3c2410fb.c > =================================================================== > --- a/drivers/video/s3c2410fb.c 2009-02-02 11:30:38.372867510 +0000 > +++ b/drivers/video/s3c2410fb.c 2009-02-02 11:30:58.703595503 +0000 > @@ -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 > 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 > 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 > > 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 > > 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 > > 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 platf > int irq; > > unregister_framebuffer(fbinfo); > + s3c2410fb_cpufreq_deregister(info); > > s3c2410fb_lcd_enable(info, 0); > msleep(1); > Index: b/drivers/video/s3c2410fb.h > =================================================================== > --- a/drivers/video/s3c2410fb.h 2009-02-02 11:29:48.488096579 +0000 > +++ b/drivers/video/s3c2410fb.h 2009-02-02 11:30:58.723594471 +0000 > @@ -29,8 +29,13 @@ struct s3c2410fb_info { > enum s3c_drv_type drv_type; > struct s3c2410fb_hw regs; > > + unsigned long clk_rate; > unsigned int palette_ready; > > +#ifdef CONFIG_CPU_FREQ > + struct notifier_block freq_transition; > +#endif > + > /* keep these registers in case we need to re-write palette */ > u32 palette_buffer[256]; > u32 pseudo_pal[16]; > afacit freq_transition.priority never gets initialised. afacit this is a cpufreq bug, as cpufreq_register_notifier() has no interface to set the notifier_block.priority and probably it's not the role of cpufreq clients to be diddling the notifier priority. I'd expect this problem to trigger kmemcheck warnings, at least. |