diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2162b86..b1b590e 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/cpufreq.h>
 
 #include <asm/mach/map.h>
 
@@ -40,6 +41,11 @@
 #define DA850_REF_FREQ		24000000
 
 #define CFGCHIP3_ASYNC3_CLKSRC	BIT(4)
+#define CFGCHIP0_PLL_MASTER_LOCK	BIT(4)
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate);
+static int da850_round_armrate(struct clk *clk, unsigned long rate);
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
 
 static struct pll_data pll0_data = {
 	.num		= 1,
@@ -57,6 +63,7 @@ static struct clk pll0_clk = {
 	.parent		= &ref_clk,
 	.pll_data	= &pll0_data,
 	.flags		= CLK_PLL,
+	.set_rate	= da850_set_pll0rate,
 };
 
 static struct clk pll0_aux_clk = {
@@ -283,6 +290,8 @@ static struct clk arm_clk = {
 	.parent		= &pll0_sysclk6,
 	.lpsc		= DA8XX_LPSC0_ARM,
 	.flags		= ALWAYS_ENABLED,
+	.set_rate	= da850_set_armrate,
+	.round_rate	= da850_round_armrate,
 };
 
 static struct clk rmii_clk = {
@@ -821,6 +830,153 @@ static void da850_set_async3_src(int pllnum)
 	__raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
 }
 
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Notes:
+ * According to the TRM, minimum PLLM results in maximum power savings.
+ * The OPP definitions below should keep the PLLM as low as possible.
+ *
+ * The output of the PLLM must be between 400 to 600 MHz.
+ * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
+ */
+struct da850_opp {
+	unsigned int	freq;	/* in KHz */
+	unsigned int	prediv;
+	unsigned int	mult;
+	unsigned int	postdiv;
+};
+
+static const struct da850_opp da850_opp_300 = {
+	.freq		= 300000,
+	.prediv		= 1,
+	.mult		= 25,
+	.postdiv	= 2,
+};
+
+static const struct da850_opp da850_opp_200 = {
+	.freq		= 200000,
+	.prediv		= 1,
+	.mult		= 25,
+	.postdiv	= 3,
+};
+
+static const struct da850_opp da850_opp_96 = {
+	.freq		= 96000,
+	.prediv		= 1,
+	.mult		= 20,
+	.postdiv	= 5,
+};
+
+#define OPP(freq) 		\
+	{				\
+		.index = (unsigned int) &da850_opp_##freq,	\
+		.frequency = freq * 1000, \
+	}
+
+static struct cpufreq_frequency_table da850_freq_table[] = {
+	OPP(300),
+	OPP(200),
+	OPP(96),
+	{
+		.index		= 0,
+		.frequency	= CPUFREQ_TABLE_END,
+	},
+};
+
+static void da850_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+	*table = &da850_freq_table[0];
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+	int i, ret = 0, diff;
+	unsigned int best = (unsigned int) -1;
+
+	rate /= 1000; /* convert to kHz */
+
+	for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		diff = da850_freq_table[i].frequency - rate;
+		if (diff < 0)
+			diff = -diff;
+
+		if (diff < best) {
+			best = diff;
+			ret = da850_freq_table[i].frequency;
+		}
+	}
+
+	return ret * 1000;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long armrate)
+{
+	struct clk *pllclk = &pll0_clk;
+
+	return clk_set_rate(pllclk, armrate);
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+	int i;
+	unsigned int prediv, mult, postdiv;
+	struct da850_opp *opp;
+	struct pll_data *pll = clk->pll_data;
+	unsigned int v;
+	int ret;
+
+	/* convert to KHz */
+	armrate /= 1000;
+
+	for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (armrate == da850_freq_table[i].frequency)
+			break;
+	}
+
+	if (da850_freq_table[i].frequency == CPUFREQ_TABLE_END) {
+		printk(KERN_WARNING "%s: Unsupported ARM clock rate %ld\n",
+							__func__, armrate);
+		return -EINVAL;
+	}
+
+	opp = (struct da850_opp *) da850_freq_table[i].index;
+	prediv = opp->prediv;
+	mult = opp->mult;
+	postdiv = opp->postdiv;
+
+	/* Unlock writing to PLL registers */
+	v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+	v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+	__raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+
+	ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
+	if (WARN_ON(ret))
+		return ret;
+
+	return 0;
+}
+#else
+static void da850_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+	*table = NULL;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate)
+{
+	return -EINVAL;
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+	return -EINVAL;
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+	return clk->rate;
+}
+#endif
+
 static struct davinci_soc_info davinci_soc_info_da850 = {
 	.io_desc		= da850_io_desc,
 	.io_desc_num		= ARRAY_SIZE(da850_io_desc),
@@ -841,6 +997,7 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
 	.gpio_irq		= IRQ_DA8XX_GPIO0,
 	.serial_dev		= &da8xx_serial_device,
 	.emac_pdata		= &da8xx_emac_pdata,
+	.init_cpufreq_table	= da850_init_cpufreq_table,
 };
 
 void __init da850_init(void)
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 325c15e..bc98a92 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -34,6 +34,7 @@ extern void __iomem *da8xx_syscfg_base;
 #define DA8XX_SYSCFG_BASE	(IO_PHYS + 0x14000)
 #define DA8XX_SYSCFG_VIRT(x)	(da8xx_syscfg_base + (x))
 #define DA8XX_JTAG_ID_REG	0x18
+#define DA8XX_CFGCHIP0_REG	0x17c
 #define DA8XX_CFGCHIP3_REG	0x188
 
 #define DA8XX_PSC0_BASE		0x01c10000
