Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2006-2008 Simtec Electronics
  3 *	http://armlinux.simtec.co.uk/
  4 *	Ben Dooks <ben@simtec.co.uk>
  5 *
  6 * S3C2410 CPU Frequency scaling
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License version 2 as
 10 * published by the Free Software Foundation.
 11*/
 12
 13#include <linux/init.h>
 14#include <linux/module.h>
 15#include <linux/interrupt.h>
 16#include <linux/ioport.h>
 17#include <linux/cpufreq.h>
 18#include <linux/device.h>
 19#include <linux/clk.h>
 20#include <linux/err.h>
 21#include <linux/io.h>
 22
 23#include <asm/mach/arch.h>
 24#include <asm/mach/map.h>
 25
 26#include <mach/regs-clock.h>
 27
 28#include <plat/cpu.h>
 29#include <plat/clock.h>
 30#include <plat/cpu-freq-core.h>
 31
 32/* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */
 33
 34static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
 35{
 36	u32 clkdiv = 0;
 37
 38	if (cfg->divs.h_divisor == 2)
 39		clkdiv |= S3C2410_CLKDIVN_HDIVN;
 40
 41	if (cfg->divs.p_divisor != cfg->divs.h_divisor)
 42		clkdiv |= S3C2410_CLKDIVN_PDIVN;
 43
 44	__raw_writel(clkdiv, S3C2410_CLKDIVN);
 45}
 46
 47static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
 48{
 49	unsigned long hclk, fclk, pclk;
 50	unsigned int hdiv, pdiv;
 51	unsigned long hclk_max;
 52
 53	fclk = cfg->freq.fclk;
 54	hclk_max = cfg->max.hclk;
 55
 56	cfg->freq.armclk = fclk;
 57
 58	s3c_freq_dbg("%s: fclk is %lu, max hclk %lu\n",
 59		      __func__, fclk, hclk_max);
 60
 61	hdiv = (fclk > cfg->max.hclk) ? 2 : 1;
 62	hclk = fclk / hdiv;
 63
 64	if (hclk > cfg->max.hclk) {
 65		s3c_freq_dbg("%s: hclk too big\n", __func__);
 66		return -EINVAL;
 67	}
 68
 69	pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
 70	pclk = hclk / pdiv;
 71
 72	if (pclk > cfg->max.pclk) {
 73		s3c_freq_dbg("%s: pclk too big\n", __func__);
 74		return -EINVAL;
 75	}
 76
 77	pdiv *= hdiv;
 78
 79	/* record the result */
 80	cfg->divs.p_divisor = pdiv;
 81	cfg->divs.h_divisor = hdiv;
 82
 83	return 0;
 84}
 85
 86static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
 87	.max		= {
 88		.fclk	= 200000000,
 89		.hclk	= 100000000,
 90		.pclk	=  50000000,
 91	},
 92
 93	/* transition latency is about 5ms worst-case, so
 94	 * set 10ms to be sure */
 95	.latency	= 10000000,
 96
 97	.locktime_m	= 150,
 98	.locktime_u	= 150,
 99	.locktime_bits	= 12,
100
101	.need_pll	= 1,
102
103	.name		= "s3c2410",
104	.calc_iotiming	= s3c2410_iotiming_calc,
105	.set_iotiming	= s3c2410_iotiming_set,
106	.get_iotiming	= s3c2410_iotiming_get,
107	.resume_clocks	= s3c2410_setup_clocks,
108
109	.set_fvco	= s3c2410_set_fvco,
110	.set_refresh	= s3c2410_cpufreq_setrefresh,
111	.set_divs	= s3c2410_cpufreq_setdivs,
112	.calc_divs	= s3c2410_cpufreq_calcdivs,
113
114	.debug_io_show	= s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
115};
116
117static int s3c2410_cpufreq_add(struct device *dev,
118			       struct subsys_interface *sif)
119{
120	return s3c_cpufreq_register(&s3c2410_cpufreq_info);
121}
122
123static struct subsys_interface s3c2410_cpufreq_interface = {
124	.name		= "s3c2410_cpufreq",
125	.subsys		= &s3c2410_subsys,
126	.add_dev	= s3c2410_cpufreq_add,
127};
128
129static int __init s3c2410_cpufreq_init(void)
130{
131	return subsys_interface_register(&s3c2410_cpufreq_interface);
132}
133arch_initcall(s3c2410_cpufreq_init);
134
135static int s3c2410a_cpufreq_add(struct device *dev,
136				struct subsys_interface *sif)
137{
138	/* alter the maximum freq settings for S3C2410A. If a board knows
139	 * it only has a maximum of 200, then it should register its own
140	 * limits. */
141
142	s3c2410_cpufreq_info.max.fclk = 266000000;
143	s3c2410_cpufreq_info.max.hclk = 133000000;
144	s3c2410_cpufreq_info.max.pclk =  66500000;
145	s3c2410_cpufreq_info.name = "s3c2410a";
146
147	return s3c2410_cpufreq_add(dev, sif);
148}
149
150static struct subsys_interface s3c2410a_cpufreq_interface = {
151	.name		= "s3c2410a_cpufreq",
152	.subsys		= &s3c2410a_subsys,
153	.add_dev	= s3c2410a_cpufreq_add,
154};
155
156static int __init s3c2410a_cpufreq_init(void)
157{
158	return subsys_interface_register(&s3c2410a_cpufreq_interface);
159}
160arch_initcall(s3c2410a_cpufreq_init);