0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/ioport.h>
0014 #include <linux/cpufreq.h>
0015 #include <linux/device.h>
0016 #include <linux/clk.h>
0017 #include <linux/err.h>
0018 #include <linux/io.h>
0019 #include <linux/soc/samsung/s3c-cpufreq-core.h>
0020 #include <linux/soc/samsung/s3c-pm.h>
0021
0022 #include <asm/mach/arch.h>
0023 #include <asm/mach/map.h>
0024
0025 #define S3C2410_CLKDIVN_PDIVN (1<<0)
0026 #define S3C2410_CLKDIVN_HDIVN (1<<1)
0027
0028
0029
0030 static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
0031 {
0032 u32 clkdiv = 0;
0033
0034 if (cfg->divs.h_divisor == 2)
0035 clkdiv |= S3C2410_CLKDIVN_HDIVN;
0036
0037 if (cfg->divs.p_divisor != cfg->divs.h_divisor)
0038 clkdiv |= S3C2410_CLKDIVN_PDIVN;
0039
0040 s3c24xx_write_clkdivn(clkdiv);
0041 }
0042
0043 static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
0044 {
0045 unsigned long hclk, fclk, pclk;
0046 unsigned int hdiv, pdiv;
0047 unsigned long hclk_max;
0048
0049 fclk = cfg->freq.fclk;
0050 hclk_max = cfg->max.hclk;
0051
0052 cfg->freq.armclk = fclk;
0053
0054 s3c_freq_dbg("%s: fclk is %lu, max hclk %lu\n",
0055 __func__, fclk, hclk_max);
0056
0057 hdiv = (fclk > cfg->max.hclk) ? 2 : 1;
0058 hclk = fclk / hdiv;
0059
0060 if (hclk > cfg->max.hclk) {
0061 s3c_freq_dbg("%s: hclk too big\n", __func__);
0062 return -EINVAL;
0063 }
0064
0065 pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
0066 pclk = hclk / pdiv;
0067
0068 if (pclk > cfg->max.pclk) {
0069 s3c_freq_dbg("%s: pclk too big\n", __func__);
0070 return -EINVAL;
0071 }
0072
0073 pdiv *= hdiv;
0074
0075
0076 cfg->divs.p_divisor = pdiv;
0077 cfg->divs.h_divisor = hdiv;
0078
0079 return 0;
0080 }
0081
0082 static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
0083 .max = {
0084 .fclk = 200000000,
0085 .hclk = 100000000,
0086 .pclk = 50000000,
0087 },
0088
0089
0090
0091 .latency = 10000000,
0092
0093 .locktime_m = 150,
0094 .locktime_u = 150,
0095 .locktime_bits = 12,
0096
0097 .need_pll = 1,
0098
0099 .name = "s3c2410",
0100 .calc_iotiming = s3c2410_iotiming_calc,
0101 .set_iotiming = s3c2410_iotiming_set,
0102 .get_iotiming = s3c2410_iotiming_get,
0103
0104 .set_fvco = s3c2410_set_fvco,
0105 .set_refresh = s3c2410_cpufreq_setrefresh,
0106 .set_divs = s3c2410_cpufreq_setdivs,
0107 .calc_divs = s3c2410_cpufreq_calcdivs,
0108
0109 .debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
0110 };
0111
0112 static int s3c2410_cpufreq_add(struct device *dev,
0113 struct subsys_interface *sif)
0114 {
0115 return s3c_cpufreq_register(&s3c2410_cpufreq_info);
0116 }
0117
0118 static struct subsys_interface s3c2410_cpufreq_interface = {
0119 .name = "s3c2410_cpufreq",
0120 .subsys = &s3c2410_subsys,
0121 .add_dev = s3c2410_cpufreq_add,
0122 };
0123
0124 static int __init s3c2410_cpufreq_init(void)
0125 {
0126 return subsys_interface_register(&s3c2410_cpufreq_interface);
0127 }
0128 arch_initcall(s3c2410_cpufreq_init);
0129
0130 static int s3c2410a_cpufreq_add(struct device *dev,
0131 struct subsys_interface *sif)
0132 {
0133
0134
0135
0136
0137 s3c2410_cpufreq_info.max.fclk = 266000000;
0138 s3c2410_cpufreq_info.max.hclk = 133000000;
0139 s3c2410_cpufreq_info.max.pclk = 66500000;
0140 s3c2410_cpufreq_info.name = "s3c2410a";
0141
0142 return s3c2410_cpufreq_add(dev, sif);
0143 }
0144
0145 static struct subsys_interface s3c2410a_cpufreq_interface = {
0146 .name = "s3c2410a_cpufreq",
0147 .subsys = &s3c2410a_subsys,
0148 .add_dev = s3c2410a_cpufreq_add,
0149 };
0150
0151 static int __init s3c2410a_cpufreq_init(void)
0152 {
0153 return subsys_interface_register(&s3c2410a_cpufreq_interface);
0154 }
0155 arch_initcall(s3c2410a_cpufreq_init);