Signed-off-by: Tero Kristo <[email protected]>
---
 arch/arm/mach-omap2/vc.c |  166 ++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 138 insertions(+), 28 deletions(-)

diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 16fa912..c50e598 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -1,14 +1,18 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
 
 #include <plat/cpu.h>
+#include <plat/prcm.h>
 
 #include "voltage.h"
 #include "vc.h"
 #include "prm-regbits-34xx.h"
 #include "prm-regbits-44xx.h"
 #include "prm44xx.h"
+#include "scrm44xx.h"
 
 /**
  * struct omap_vc_channel_cfg - describe the cfg_channel bitfield
@@ -194,44 +198,156 @@ int omap_vc_bypass_scale(struct voltagedomain *voltdm,
        return 0;
 }
 
-static void __init omap3_vfsm_init(struct voltagedomain *voltdm)
+static void omap3_set_ret_timings(struct voltagedomain *voltdm)
 {
-       /*
-        * Voltage Manager FSM parameters init
-        * XXX This data should be passed in from the board file
-        */
-       voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET);
-       voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET);
-       voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET);
+       unsigned long voltsetup1;
+       struct clk *sys_ck;
+       u32 sys_clk_rate;
+
+       sys_ck = clk_get(NULL, "sys_ck");
+       if (IS_ERR(sys_ck)) {
+               pr_warning("%s: unable to get sys_ck to calculate "
+                       "vdd_%s timings\n", __func__, voltdm->name);
+               return;
+       }
+       sys_clk_rate = clk_get_rate(sys_ck);
+       clk_put(sys_ck);
+
+       voltsetup1 = (voltdm->vc_param->on - voltdm->vc_param->ret) /
+                       voltdm->pmic->slew_rate;
+
+       voltsetup1 = voltsetup1 * sys_clk_rate / 8 / 1000000 + 1;
+       voltdm->rmw(voltdm->vfsm->voltsetup_mask,
+               voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask),
+               voltdm->vfsm->voltsetup_reg);
+
+       /* set voltsetup 2 to 0 */
+       voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET);
+}
+
+static void omap3_set_off_timings(struct voltagedomain *voltdm)
+{
+       unsigned long clksetup;
+       unsigned long voltsetup2;
+
+       clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET);
+
+       /* voltsetup 2 in us */
+       voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate;
+
+       /* convert to 32k clk cycles */
+       voltsetup2 = voltsetup2 * 32768 / 1000000 + 1;
+
+       voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET);
+
+       /* set voltsetup1 to 0 */
+       voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0,
+               voltdm->vfsm->voltsetup_reg);
+
+       /* set voltoffset */
+       voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET);
 }
 
 static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
 {
-       static bool is_initialized;
+       omap3_set_off_timings(voltdm);
+}
 
-       if (is_initialized)
-               return;
+static u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff,
+               u32 clk_rate)
+{
+       u32 prescaler;
+       u32 cycles;
+       u32 time;
+
+       time = voltage_diff / voltdm->pmic->slew_rate;
+
+       cycles = clk_rate / 1000 * time;
+
+       cycles /= 64;
+       prescaler = 0;
+
+       /* shift to next prescaler until no overflow */
+
+       /* scale for div 256 = 64 * 4 */
+       if (cycles > 63) {
+               cycles /= 4;
+               prescaler++;
+       }
+
+       /* scale for div 512 = 256 * 2 */
+       if (cycles > 63) {
+               cycles /= 2;
+               prescaler++;
+       }
+
+       /* scale for div 2048 = 512 * 4 */
+       if (cycles > 63) {
+               cycles /= 4;
+               prescaler++;
+       }
+
+       /* check for overflow => invalid ramp time */
+       if (cycles > 63) {
+               pr_warning("%s: invalid setuptime for vdd_%s\n", __func__,
+                       voltdm->name);
+               return 0;
+       }
 
-       omap3_vfsm_init(voltdm);
+       cycles++;
 
-       is_initialized = true;
+       return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) |
+               (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT);
 }
 
+static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode)
+{
+       struct clk *sys_ck;
+       u32 sys_clk_rate;
+       u32 val;
+       u32 ramp;
+
+       sys_ck = clk_get(NULL, "sys_clkin_ck");
+       if (IS_ERR(sys_ck)) {
+               pr_warning("%s: unable to get sys_ck to calculate "
+                       "vdd_%s timings\n", __func__, voltdm->name);
+               return;
+       }
+       sys_clk_rate = clk_get_rate(sys_ck);
+       clk_put(sys_ck);
+
+       /* configure the setup times */
+       val = voltdm->read(voltdm->vfsm->voltsetup_reg);
+
+       if (off_mode)
+               ramp = omap4_calc_volt_ramp(voltdm,
+                       voltdm->vc_param->on - voltdm->vc_param->off,
+                       sys_clk_rate);
+       else
+               ramp = omap4_calc_volt_ramp(voltdm,
+                       voltdm->vc_param->on - voltdm->vc_param->ret,
+                       sys_clk_rate);
+
+       if (!ramp)
+               return;
+
+       val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT;
+
+       val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT;
+
+       voltdm->write(val, voltdm->vfsm->voltsetup_reg);
+}
 
 /* OMAP4 specific voltage init functions */
 static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
 {
-       static bool is_initialized;
        u32 vc_val;
 
-       if (is_initialized)
-               return;
+       omap4_set_timings(voltdm, true);
 
        /* XXX These are magic numbers and do not belong! */
        vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT);
        voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
-
-       is_initialized = true;
 }
 
 /**
@@ -305,7 +421,6 @@ void __init omap_vc_init_channel(struct voltagedomain 
*voltdm)
        vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr;
        vc->volt_reg_addr = voltdm->pmic->volt_reg_addr;
        vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr;
-       vc->setup_time = voltdm->pmic->volt_setup_time;
 
        /* Configure the i2c slave address for this VC */
        voltdm->rmw(vc->smps_sa_mask,
@@ -329,10 +444,10 @@ void __init omap_vc_init_channel(struct voltagedomain 
*voltdm)
        }
 
        /* Set up the on, inactive, retention and off voltage */
-       on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt);
-       onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt);
-       ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt);
-       off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt);
+       on_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->on);
+       onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->onlp);
+       ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->ret);
+       off_vsel = voltdm->pmic->uv_to_vsel(voltdm->vc_param->off);
        val = ((on_vsel << vc->common->cmd_on_shift) |
               (onlp_vsel << vc->common->cmd_onlp_shift) |
               (ret_vsel << vc->common->cmd_ret_shift) |
@@ -343,11 +458,6 @@ void __init omap_vc_init_channel(struct voltagedomain 
*voltdm)
        /* Channel configuration */
        omap_vc_config_channel(voltdm);
 
-       /* Configure the setup times */
-       voltdm->rmw(voltdm->vfsm->voltsetup_mask,
-                   vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask),
-                   voltdm->vfsm->voltsetup_reg);
-
        omap_vc_i2c_init(voltdm);
 
        if (cpu_is_omap34xx())
-- 
1.7.4.1


Texas Instruments Oy, Porkkalankatu 22, 00180 Helsinki, Finland. Business ID: 
0115040-6. Domicile: Helsinki
 

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to