0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/types.h>
0019 #include <linux/cpufreq.h>
0020 #include <linux/init.h>
0021 #include <linux/err.h>
0022 #include <linux/clk.h>
0023 #include <linux/platform_data/davinci-cpufreq.h>
0024 #include <linux/platform_device.h>
0025 #include <linux/export.h>
0026
0027 struct davinci_cpufreq {
0028 struct device *dev;
0029 struct clk *armclk;
0030 struct clk *asyncclk;
0031 unsigned long asyncrate;
0032 };
0033 static struct davinci_cpufreq cpufreq;
0034
0035 static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
0036 {
0037 struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
0038 struct clk *armclk = cpufreq.armclk;
0039 unsigned int old_freq, new_freq;
0040 int ret = 0;
0041
0042 old_freq = policy->cur;
0043 new_freq = pdata->freq_table[idx].frequency;
0044
0045
0046 if (pdata->set_voltage && new_freq > old_freq) {
0047 ret = pdata->set_voltage(idx);
0048 if (ret)
0049 return ret;
0050 }
0051
0052 ret = clk_set_rate(armclk, new_freq * 1000);
0053 if (ret)
0054 return ret;
0055
0056 if (cpufreq.asyncclk) {
0057 ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
0058 if (ret)
0059 return ret;
0060 }
0061
0062
0063 if (pdata->set_voltage && new_freq < old_freq)
0064 pdata->set_voltage(idx);
0065
0066 return 0;
0067 }
0068
0069 static int davinci_cpu_init(struct cpufreq_policy *policy)
0070 {
0071 int result = 0;
0072 struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
0073 struct cpufreq_frequency_table *freq_table = pdata->freq_table;
0074
0075 if (policy->cpu != 0)
0076 return -EINVAL;
0077
0078
0079 if (pdata->init) {
0080 result = pdata->init();
0081 if (result)
0082 return result;
0083 }
0084
0085 policy->clk = cpufreq.armclk;
0086
0087
0088
0089
0090
0091
0092
0093 cpufreq_generic_init(policy, freq_table, 2000 * 1000);
0094 return 0;
0095 }
0096
0097 static struct cpufreq_driver davinci_driver = {
0098 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0099 .verify = cpufreq_generic_frequency_table_verify,
0100 .target_index = davinci_target,
0101 .get = cpufreq_generic_get,
0102 .init = davinci_cpu_init,
0103 .name = "davinci",
0104 .attr = cpufreq_generic_attr,
0105 };
0106
0107 static int __init davinci_cpufreq_probe(struct platform_device *pdev)
0108 {
0109 struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
0110 struct clk *asyncclk;
0111
0112 if (!pdata)
0113 return -EINVAL;
0114 if (!pdata->freq_table)
0115 return -EINVAL;
0116
0117 cpufreq.dev = &pdev->dev;
0118
0119 cpufreq.armclk = clk_get(NULL, "arm");
0120 if (IS_ERR(cpufreq.armclk)) {
0121 dev_err(cpufreq.dev, "Unable to get ARM clock\n");
0122 return PTR_ERR(cpufreq.armclk);
0123 }
0124
0125 asyncclk = clk_get(cpufreq.dev, "async");
0126 if (!IS_ERR(asyncclk)) {
0127 cpufreq.asyncclk = asyncclk;
0128 cpufreq.asyncrate = clk_get_rate(asyncclk);
0129 }
0130
0131 return cpufreq_register_driver(&davinci_driver);
0132 }
0133
0134 static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
0135 {
0136 clk_put(cpufreq.armclk);
0137
0138 if (cpufreq.asyncclk)
0139 clk_put(cpufreq.asyncclk);
0140
0141 return cpufreq_unregister_driver(&davinci_driver);
0142 }
0143
0144 static struct platform_driver davinci_cpufreq_driver = {
0145 .driver = {
0146 .name = "cpufreq-davinci",
0147 },
0148 .remove = __exit_p(davinci_cpufreq_remove),
0149 };
0150
0151 int __init davinci_cpufreq_init(void)
0152 {
0153 return platform_driver_probe(&davinci_cpufreq_driver,
0154 davinci_cpufreq_probe);
0155 }
0156