Commit 0dac6ecd authored by Ben Dooks's avatar Ben Dooks Committed by Linus Torvalds
Browse files

s3c-fb: CPUFREQ frequency scaling support



Add support for CPU frequency scaling in the S3C24XX video driver.

Signed-off-by: default avatarSimtec Linux Team <linux@simtec.co.uk>
Signed-off-by: default avatarBen Dooks <ben@simtec.co.uk>
Cc: Dave Jones <davej@codemonkey.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ddc518d9
Loading
Loading
Loading
Loading
+65 −2
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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];