msm: krait-regulator-pmic: workaround for soft start issue

There is hw bug in FTS2 where if the gang is disabled and enabled in a
single phase configuration, the subsequent addition of phases do not see
the SS done flag of the gang leader and as a result use SS_CTL timings
for voltage stepping instead of VS_CTL settings.

The sw workaround is to update SS_CTL to the same timing as VS_CTL when
phases are added. Also when the gang is disabled switch back to original
SS_CTL to allow for quick startup when enabled.

Moreover, the recommended settling time after a phase increase with this
workaround is 100uS instead of 50uS. Update the code for this as well.

CRs-Fixed: 640655
Change-Id: I732b526152e581231af19b4aac05b1500a68712e
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
This commit is contained in:
Abhijeet Dharmapurikar 2014-04-09 12:45:34 -07:00
parent fb7090ec4d
commit d3136affb9
4 changed files with 113 additions and 7 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -53,13 +53,14 @@
#define REG_PHASE_CTL 0x52 #define REG_PHASE_CTL 0x52
#define BALANCE_EN_BIT BIT(7) #define BALANCE_EN_BIT BIT(7)
#define REG_SS_CTL 0x60
#define REG_VS_CTL 0x61 #define REG_VS_CTL 0x61
#define VS_CTL_VAL 0x82 #define VS_CTL_VAL 0x82
#define REG_GANG_CTL2 0xC1 #define REG_GANG_CTL2 0xC1
#define GANG_EN_BIT BIT(7) #define GANG_EN_BIT BIT(7)
#define REG_PWM_CL 0x60 #define REG_PWM_CL 0x60
struct krait_vreg_pmic_chip { struct krait_vreg_pmic_chip {
struct spmi_device *spmi; struct spmi_device *spmi;
@ -69,6 +70,9 @@ struct krait_vreg_pmic_chip {
u8 ctrl_dig_major; u8 ctrl_dig_major;
u8 ctrl_dig_minor; u8 ctrl_dig_minor;
u32 unexpected_config; u32 unexpected_config;
u8 orig_ss_ctl;
u8 wrkarnd_ss_ctl;
bool is_ss_same_as_vs_ctl;
struct dentry *dent; struct dentry *dent;
}; };
@ -119,6 +123,62 @@ static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
return 0; return 0;
} }
/**
* krait_pmic_pre_disable - workarounds after enabling
*
* Context: Can be called in atomic context
*
* Returns: 0 on success, error code on failure
*/
int krait_pmic_pre_disable(void)
{
int rc = 0;
if (the_chip == NULL) {
pr_debug("krait_regulator_pmic not ready yet\n");
return 0;
}
if (the_chip->is_ss_same_as_vs_ctl == true) {
the_chip->is_ss_same_as_vs_ctl = false;
rc = write_byte(the_chip->spmi,
the_chip->ctrl_base + REG_SS_CTL,
&the_chip->orig_ss_ctl);
pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n",
the_chip->orig_ss_ctl, the_chip->spmi->sid,
the_chip->ctrl_base + REG_SS_CTL, rc);
}
return rc;
}
/**
* krait_pmic_pre_multiphase_enable - workarounds after enabling
*
* Context: Can be called in atomic context
*
* Returns: 0 on success, error code on failure
*/
int krait_pmic_pre_multiphase_enable(void)
{
int rc = 0;
if (the_chip == NULL) {
pr_debug("krait_regulator_pmic not ready yet\n");
return 0;
}
if (the_chip->is_ss_same_as_vs_ctl == false) {
the_chip->is_ss_same_as_vs_ctl = true;
rc = write_byte(the_chip->spmi,
the_chip->ctrl_base + REG_SS_CTL,
&the_chip->wrkarnd_ss_ctl);
pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n",
the_chip->wrkarnd_ss_ctl, the_chip->spmi->sid,
the_chip->ctrl_base + REG_SS_CTL, rc);
}
return rc;
}
#define ISTEP_MA 500 #define ISTEP_MA 500
#define IOFFSET_MA 1000 #define IOFFSET_MA 1000
#define OVERSHOOT_DIG_MAJOR 1 #define OVERSHOOT_DIG_MAJOR 1
@ -144,7 +204,7 @@ static bool v_overshoot_fixed(void)
bool krait_pmic_is_ready(void) bool krait_pmic_is_ready(void)
{ {
if (the_chip == NULL) { if (the_chip == NULL) {
pr_debug("kait_regulator_pmic not ready yet\n"); pr_debug("krait_regulator_pmic not ready yet\n");
return false; return false;
} }
return true; return true;
@ -166,7 +226,7 @@ int krait_pmic_post_pfm_entry(void)
int rc; int rc;
if (the_chip == NULL) { if (the_chip == NULL) {
pr_debug("kait_regulator_pmic not ready yet\n"); pr_debug("krait_regulator_pmic not ready yet\n");
return -ENXIO; return -ENXIO;
} }
@ -197,7 +257,7 @@ int krait_pmic_post_pwm_entry(void)
int rc; int rc;
if (the_chip == NULL) { if (the_chip == NULL) {
pr_debug("kait_regulator_pmic not ready yet\n"); pr_debug("krait_regulator_pmic not ready yet\n");
return -ENXIO; return -ENXIO;
} }
@ -347,6 +407,7 @@ static int gang_configuration_check(struct krait_vreg_pmic_chip *chip)
return 0; return 0;
} }
#define REG_SS_CTL_MASK 0x0F
static int krait_vreg_pmic_probe(struct spmi_device *spmi) static int krait_vreg_pmic_probe(struct spmi_device *spmi)
{ {
u8 type, subtype; u8 type, subtype;
@ -426,6 +487,16 @@ static int krait_vreg_pmic_probe(struct spmi_device *spmi)
if (rc) if (rc)
return rc; return rc;
READ_BYTE(chip, chip->ctrl_base + REG_SS_CTL, chip->orig_ss_ctl, rc);
if (rc)
return rc;
READ_BYTE(chip, chip->ctrl_base + REG_VS_CTL, chip->wrkarnd_ss_ctl, rc);
if (rc)
return rc;
chip->wrkarnd_ss_ctl &= REG_SS_CTL_MASK;
gang_configuration_check(chip); gang_configuration_check(chip);
chip->dent = debugfs_create_dir("krait-regulator-pmic", NULL); chip->dent = debugfs_create_dir("krait-regulator-pmic", NULL);

View File

@ -480,7 +480,7 @@ static bool enable_phase_management(struct pmic_gang_vreg *pvreg)
#define TWO_PHASE_COEFF 2000000 #define TWO_PHASE_COEFF 2000000
#define PWM_SETTLING_TIME_US 50 #define PWM_SETTLING_TIME_US 50
#define PHASE_SETTLING_TIME_US 50 #define PHASE_SETTLING_TIME_US 100
static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from, static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
int coeff_total) int coeff_total)
{ {
@ -560,6 +560,13 @@ static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
mb(); mb();
} }
if (phase_count >= 2) {
rc = krait_pmic_pre_multiphase_enable();
if (rc < 0) {
pr_err("%s failed to run pre multiphase steps %d rc = %d\n",
from->name, phase_count, rc);
}
}
rc = set_pmic_gang_phases(pvreg, phase_count); rc = set_pmic_gang_phases(pvreg, phase_count);
if (rc < 0) { if (rc < 0) {
pr_err("%s failed set phase %d rc = %d\n", pr_err("%s failed set phase %d rc = %d\n",

View File

@ -30,6 +30,7 @@
#include <soc/qcom/pm.h> #include <soc/qcom/pm.h>
#include <soc/qcom/rpm-notifier.h> #include <soc/qcom/rpm-notifier.h>
#include <soc/qcom/event_timer.h> #include <soc/qcom/event_timer.h>
#include <soc/qcom/krait-regulator-pmic.h>
#define SCLK_HZ (32768) #define SCLK_HZ (32768)
@ -205,6 +206,7 @@ static int lpm_set_l2_mode(struct lpm_system_state *system_state,
switch (sleep_mode) { switch (sleep_mode) {
case MSM_SPM_L2_MODE_POWER_COLLAPSE: case MSM_SPM_L2_MODE_POWER_COLLAPSE:
krait_pmic_pre_disable();
msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF); msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
break; break;
case MSM_SPM_L2_MODE_GDHS: case MSM_SPM_L2_MODE_GDHS:

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -12,7 +12,33 @@
#ifndef __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H #ifndef __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
#define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H #define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
#ifdef CONFIG_KRAIT_REGULATOR
bool krait_pmic_is_ready(void); bool krait_pmic_is_ready(void);
int krait_pmic_post_pfm_entry(void); int krait_pmic_post_pfm_entry(void);
int krait_pmic_post_pwm_entry(void); int krait_pmic_post_pwm_entry(void);
int krait_pmic_pre_disable(void);
int krait_pmic_pre_multiphase_enable(void);
#else
bool krait_pmic_is_ready(void)
{
return false;
}
int krait_pmic_post_pfm_entry(void)
{
return -ENXIO;
}
int krait_pmic_post_pwm_entry(void)
{
return -ENXIO;
}
int krait_pmic_pre_disable(void)
{
return 0;
}
int krait_pmic_pre_multiphase_enable(void)
{
return 0;
}
#endif
#endif #endif