aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/da850.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-davinci/da850.c')
-rw-r--r--arch/arm/mach-davinci/da850.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a62863c57459..49dcc71168c7 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/cpufreq.h>
18 19
19#include <asm/mach/map.h> 20#include <asm/mach/map.h>
20 21
@@ -26,6 +27,7 @@
26#include <mach/common.h> 27#include <mach/common.h>
27#include <mach/time.h> 28#include <mach/time.h>
28#include <mach/da8xx.h> 29#include <mach/da8xx.h>
30#include <mach/cpufreq.h>
29 31
30#include "clock.h" 32#include "clock.h"
31#include "mux.h" 33#include "mux.h"
@@ -40,6 +42,11 @@
40#define DA850_REF_FREQ 24000000 42#define DA850_REF_FREQ 24000000
41 43
42#define CFGCHIP3_ASYNC3_CLKSRC BIT(4) 44#define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
45#define CFGCHIP0_PLL_MASTER_LOCK BIT(4)
46
47static int da850_set_armrate(struct clk *clk, unsigned long rate);
48static int da850_round_armrate(struct clk *clk, unsigned long rate);
49static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
43 50
44static struct pll_data pll0_data = { 51static struct pll_data pll0_data = {
45 .num = 1, 52 .num = 1,
@@ -57,6 +64,7 @@ static struct clk pll0_clk = {
57 .parent = &ref_clk, 64 .parent = &ref_clk,
58 .pll_data = &pll0_data, 65 .pll_data = &pll0_data,
59 .flags = CLK_PLL, 66 .flags = CLK_PLL,
67 .set_rate = da850_set_pll0rate,
60}; 68};
61 69
62static struct clk pll0_aux_clk = { 70static struct clk pll0_aux_clk = {
@@ -283,6 +291,8 @@ static struct clk arm_clk = {
283 .parent = &pll0_sysclk6, 291 .parent = &pll0_sysclk6,
284 .lpsc = DA8XX_LPSC0_ARM, 292 .lpsc = DA8XX_LPSC0_ARM,
285 .flags = ALWAYS_ENABLED, 293 .flags = ALWAYS_ENABLED,
294 .set_rate = da850_set_armrate,
295 .round_rate = da850_round_armrate,
286}; 296};
287 297
288static struct clk rmii_clk = { 298static struct clk rmii_clk = {
@@ -820,6 +830,149 @@ static void da850_set_async3_src(int pllnum)
820 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG)); 830 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
821} 831}
822 832
833#ifdef CONFIG_CPU_FREQ
834/*
835 * Notes:
836 * According to the TRM, minimum PLLM results in maximum power savings.
837 * The OPP definitions below should keep the PLLM as low as possible.
838 *
839 * The output of the PLLM must be between 400 to 600 MHz.
840 * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
841 */
842struct da850_opp {
843 unsigned int freq; /* in KHz */
844 unsigned int prediv;
845 unsigned int mult;
846 unsigned int postdiv;
847};
848
849static const struct da850_opp da850_opp_300 = {
850 .freq = 300000,
851 .prediv = 1,
852 .mult = 25,
853 .postdiv = 2,
854};
855
856static const struct da850_opp da850_opp_200 = {
857 .freq = 200000,
858 .prediv = 1,
859 .mult = 25,
860 .postdiv = 3,
861};
862
863static const struct da850_opp da850_opp_96 = {
864 .freq = 96000,
865 .prediv = 1,
866 .mult = 20,
867 .postdiv = 5,
868};
869
870#define OPP(freq) \
871 { \
872 .index = (unsigned int) &da850_opp_##freq, \
873 .frequency = freq * 1000, \
874 }
875
876static struct cpufreq_frequency_table da850_freq_table[] = {
877 OPP(300),
878 OPP(200),
879 OPP(96),
880 {
881 .index = 0,
882 .frequency = CPUFREQ_TABLE_END,
883 },
884};
885
886static struct davinci_cpufreq_config cpufreq_info = {
887 .freq_table = &da850_freq_table[0],
888};
889
890static struct platform_device da850_cpufreq_device = {
891 .name = "cpufreq-davinci",
892 .dev = {
893 .platform_data = &cpufreq_info,
894 },
895};
896
897int __init da850_register_cpufreq(void)
898{
899 return platform_device_register(&da850_cpufreq_device);
900}
901
902static int da850_round_armrate(struct clk *clk, unsigned long rate)
903{
904 int i, ret = 0, diff;
905 unsigned int best = (unsigned int) -1;
906
907 rate /= 1000; /* convert to kHz */
908
909 for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
910 diff = da850_freq_table[i].frequency - rate;
911 if (diff < 0)
912 diff = -diff;
913
914 if (diff < best) {
915 best = diff;
916 ret = da850_freq_table[i].frequency;
917 }
918 }
919
920 return ret * 1000;
921}
922
923static int da850_set_armrate(struct clk *clk, unsigned long index)
924{
925 struct clk *pllclk = &pll0_clk;
926
927 return clk_set_rate(pllclk, index);
928}
929
930static int da850_set_pll0rate(struct clk *clk, unsigned long index)
931{
932 unsigned int prediv, mult, postdiv;
933 struct da850_opp *opp;
934 struct pll_data *pll = clk->pll_data;
935 unsigned int v;
936 int ret;
937
938 opp = (struct da850_opp *) da850_freq_table[index].index;
939 prediv = opp->prediv;
940 mult = opp->mult;
941 postdiv = opp->postdiv;
942
943 /* Unlock writing to PLL registers */
944 v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
945 v &= ~CFGCHIP0_PLL_MASTER_LOCK;
946 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
947
948 ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
949 if (WARN_ON(ret))
950 return ret;
951
952 return 0;
953}
954#else
955int __init da850_register_cpufreq(void)
956{
957 return 0;
958}
959
960static int da850_set_armrate(struct clk *clk, unsigned long rate)
961{
962 return -EINVAL;
963}
964
965static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
966{
967 return -EINVAL;
968}
969
970static int da850_round_armrate(struct clk *clk, unsigned long rate)
971{
972 return clk->rate;
973}
974#endif
975
823static struct davinci_soc_info davinci_soc_info_da850 = { 976static struct davinci_soc_info davinci_soc_info_da850 = {
824 .io_desc = da850_io_desc, 977 .io_desc = da850_io_desc,
825 .io_desc_num = ARRAY_SIZE(da850_io_desc), 978 .io_desc_num = ARRAY_SIZE(da850_io_desc),