|  | @@ -406,3 +406,133 @@ static __init int s3c_cpufreq_initclks(void)
 | 
	
		
			
				|  |  |  	clk_pclk = s3c_cpufreq_clk_get(NULL, "pclk");
 | 
	
		
			
				|  |  |  	clk_arm = s3c_cpufreq_clk_get(NULL, "armclk");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) ||
 | 
	
		
			
				|  |  | +	    IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: could not get clock(s)\n", __func__);
 | 
	
		
			
				|  |  | +		return -ENOENT;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	printk(KERN_INFO "%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n", __func__,
 | 
	
		
			
				|  |  | +	       clk_get_rate(clk_fclk) / 1000,
 | 
	
		
			
				|  |  | +	       clk_get_rate(clk_hclk) / 1000,
 | 
	
		
			
				|  |  | +	       clk_get_rate(clk_pclk) / 1000,
 | 
	
		
			
				|  |  | +	       clk_get_rate(clk_arm) / 1000);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c_cpufreq_verify(struct cpufreq_policy *policy)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (policy->cpu != 0)
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef CONFIG_PM
 | 
	
		
			
				|  |  | +static struct cpufreq_frequency_table suspend_pll;
 | 
	
		
			
				|  |  | +static unsigned int suspend_freq;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	suspend_pll.frequency = clk_get_rate(_clk_mpll);
 | 
	
		
			
				|  |  | +	suspend_pll.index = __raw_readl(S3C2410_MPLLCON);
 | 
	
		
			
				|  |  | +	suspend_freq = s3c_cpufreq_get(0) * 1000;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	s3c_freq_dbg("%s: resuming with policy %p\n", __func__, policy);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	last_target = ~0;	/* invalidate last_target setting */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* first, find out what speed we resumed at. */
 | 
	
		
			
				|  |  | +	s3c_cpufreq_resume_clocks();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* whilst we will be called later on, we try and re-set the
 | 
	
		
			
				|  |  | +	 * cpu frequencies as soon as possible so that we do not end
 | 
	
		
			
				|  |  | +	 * up resuming devices and then immediately having to re-set
 | 
	
		
			
				|  |  | +	 * a number of settings once these devices have restarted.
 | 
	
		
			
				|  |  | +	 *
 | 
	
		
			
				|  |  | +	 * as a note, it is expected devices are not used until they
 | 
	
		
			
				|  |  | +	 * have been un-suspended and at that time they should have
 | 
	
		
			
				|  |  | +	 * used the updated clock settings.
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll);
 | 
	
		
			
				|  |  | +	if (ret) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: failed to reset pll/freq\n", __func__);
 | 
	
		
			
				|  |  | +		return ret;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +#define s3c_cpufreq_resume NULL
 | 
	
		
			
				|  |  | +#define s3c_cpufreq_suspend NULL
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static struct cpufreq_driver s3c24xx_driver = {
 | 
	
		
			
				|  |  | +	.flags		= CPUFREQ_STICKY,
 | 
	
		
			
				|  |  | +	.verify		= s3c_cpufreq_verify,
 | 
	
		
			
				|  |  | +	.target		= s3c_cpufreq_target,
 | 
	
		
			
				|  |  | +	.get		= s3c_cpufreq_get,
 | 
	
		
			
				|  |  | +	.init		= s3c_cpufreq_init,
 | 
	
		
			
				|  |  | +	.suspend	= s3c_cpufreq_suspend,
 | 
	
		
			
				|  |  | +	.resume		= s3c_cpufreq_resume,
 | 
	
		
			
				|  |  | +	.name		= "s3c24xx",
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int __init s3c_cpufreq_register(struct s3c_cpufreq_info *info)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (!info || !info->name) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: failed to pass valid information\n",
 | 
	
		
			
				|  |  | +		       __func__);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	printk(KERN_INFO "S3C24XX CPU Frequency driver, %s cpu support\n",
 | 
	
		
			
				|  |  | +	       info->name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* check our driver info has valid data */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	BUG_ON(info->set_refresh == NULL);
 | 
	
		
			
				|  |  | +	BUG_ON(info->set_divs == NULL);
 | 
	
		
			
				|  |  | +	BUG_ON(info->calc_divs == NULL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* info->set_fvco is optional, depending on whether there
 | 
	
		
			
				|  |  | +	 * is a need to set the clock code. */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	cpu_cur.info = info;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Note, driver registering should probably update locktime */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct s3c_cpufreq_board *ours;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!board) {
 | 
	
		
			
				|  |  | +		printk(KERN_INFO "%s: no board data\n", __func__);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Copy the board information so that each board can make this
 | 
	
		
			
				|  |  | +	 * initdata. */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ours = kzalloc(sizeof(struct s3c_cpufreq_board), GFP_KERNEL);
 | 
	
		
			
				|  |  | +	if (ours == NULL) {
 | 
	
		
			
				|  |  | +		printk(KERN_ERR "%s: no memory\n", __func__);
 | 
	
		
			
				|  |  | +		return -ENOMEM;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	*ours = *board;
 | 
	
		
			
				|  |  | +	cpu_cur.board = ours;
 | 
	
		
			
				|  |  | +
 |