msm: spm-v2: Add API to enable PFM mode on PMIC
When the Kraits are drawing the least power, the Krait buck can be put
in low power mode (PFM) as well.
The msm_spm_enable_fts_lpm() API will allow the PFM mode to be enabled
through the SPM PMIC interface.
Change-Id: Ia5fd16e27e2c90683f6ae93b1e909fa79722a091
Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index f0d3d06..17997d2 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -84,10 +84,6 @@
[MSM_SPM_REG_SAW2_VERSION] = 0xFD0,
};
-/******************************************************************************
- * Internal helper functions
- *****************************************************************************/
-
static inline uint32_t msm_spm_drv_get_num_spm_entry(
struct msm_spm_driver_data *dev)
{
@@ -150,6 +146,12 @@
{
unsigned int pmic_data = 0;
+ /**
+ * VCTL_PORT has to be 0, for PMIC_STS register to be updated.
+ * Ensure that vctl_port is always set to 0.
+ */
+ WARN_ON(dev->vctl_port);
+
pmic_data |= vlevel;
pmic_data |= (dev->vctl_port & 0x7) << 16;
@@ -213,10 +215,6 @@
return ret;
}
-/******************************************************************************
- * Public functions
- *****************************************************************************/
-
inline int msm_spm_drv_set_spm_enable(
struct msm_spm_driver_data *dev, bool enable)
{
@@ -381,69 +379,92 @@
goto set_vdd_bail;
}
- /* Set AVS min/max */
- msm_spm_drv_set_avs_vlevel(dev, vlevel);
-
if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
- pr_info("%s: done, remaining timeout %uus\n",
+ pr_info("%s: done, remaining timeout %u us\n",
__func__, timeout_us);
+ /* Set AVS min/max */
+ msm_spm_drv_set_avs_vlevel(dev, vlevel);
msm_spm_drv_enable_avs(dev);
+
return 0;
set_vdd_bail:
msm_spm_drv_enable_avs(dev);
- pr_err("%s: failed %#x, remaining timeout %uus, vlevel %#x\n",
+ pr_err("%s: failed %#x, remaining timeout %u us, vlevel %#x\n",
__func__, vlevel, timeout_us, new_level);
return -EIO;
}
-int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
- unsigned int phase_cnt)
+static int msm_spm_drv_get_pmic_port(struct msm_spm_driver_data *dev,
+ enum msm_spm_pmic_port port)
+{
+ int index = -1;
+
+ switch (port) {
+ case MSM_SPM_PMIC_VCTL_PORT:
+ index = dev->vctl_port;
+ break;
+ case MSM_SPM_PMIC_PHASE_PORT:
+ index = dev->phase_port;
+ break;
+ case MSM_SPM_PMIC_PFM_PORT:
+ index = dev->pfm_port;
+ break;
+ default:
+ break;
+ }
+
+ return index;
+}
+
+int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
+ enum msm_spm_pmic_port port, unsigned int data)
{
unsigned int pmic_data = 0;
unsigned int timeout_us = 0;
+ int index = 0;
if (dev->major != SAW2_MAJOR_2)
return -ENODEV;
- pmic_data |= phase_cnt & 0xFF;
- pmic_data |= (dev->phase_port & 0x7) << 16;
+ if (!msm_spm_pmic_arb_present(dev))
+ return -ENOSYS;
+
+ index = msm_spm_drv_get_pmic_port(dev, port);
+ if (index < 0)
+ return -ENODEV;
+
+ pmic_data |= data & 0xFF;
+ pmic_data |= (index & 0x7) << 16;
dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
mb();
- /* Wait for PMIC state to return to idle or until timeout */
timeout_us = dev->vctl_timeout_us;
- while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
- if (!timeout_us)
- goto set_phase_bail;
+ /**
+ * Confirm the pmic data set was what hardware sent by
+ * checking the PMIC FSM state.
+ * We cannot use the sts_pmic_data and check it against
+ * the value like we do fot set_vdd, since the PMIC_STS
+ * is only updated for SAW_VCTL sent with port index 0.
+ */
+ do {
+ if (msm_spm_drv_get_sts_pmic_state(dev) ==
+ MSM_SPM_PMIC_STATE_IDLE)
+ break;
+ udelay(1);
+ } while (--timeout_us);
- if (timeout_us > 10) {
- udelay(10);
- timeout_us -= 10;
- } else {
- udelay(timeout_us);
- timeout_us = 0;
- }
+ if (!timeout_us) {
+ pr_err("%s: failed, remaining timeout %u us, data %d\n",
+ __func__, timeout_us, data);
+ return -EIO;
}
- if (msm_spm_drv_get_sts_curr_pmic_data(dev) != phase_cnt)
- goto set_phase_bail;
-
- if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
- pr_info("%s: done, remaining timeout %uus\n",
- __func__, timeout_us);
-
return 0;
-
-set_phase_bail:
- pr_err("%s: failed, remaining timeout %uus, phase count %d\n",
- __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
- return -EIO;
-
}
void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
@@ -472,6 +493,7 @@
dev->vctl_port = data->vctl_port;
dev->phase_port = data->phase_port;
+ dev->pfm_port = data->pfm_port;
dev->reg_base_addr = data->reg_base_addr;
memcpy(dev->reg_shadow, data->reg_init_values,
sizeof(data->reg_init_values));