msm: spm: Update SPM driver to support SAW2 v2.0 hardware
The new hardware supports FTS switching for all Krait cores using ganged
voltage rail. There are 4 Krait SPMs and 1 L2 SPM and all instances are
rev 2.0 of the SAW hardware block. The voltage control on the Krait rail
is controlled by writing to the PMIC from the L2 SPM.
Add 2 additional APIs to set the voltage and the number of phases for the
Krait cores.
Backward compatibility with SAW rev 1.0 is maintained.
Change-Id: I650e4c3ad2a109956aef668a33bc3949284e6944
Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 2ce5268..7dfa4df 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msmcopper_pm.dtsi"
/include/ "msm-pm8841.dtsi"
/include/ "msm-pm8941.dtsi"
/include/ "msmcopper-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
new file mode 100644
index 0000000..53ad0d1
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,spm-cmd-wfi = [03 0b 0f];
+ qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ a0 b0 03 68 70 3b 92 a0 b0
+ 82 2b 50 10 30 02 22 30 0f];
+ qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,spm-cmd-wfi = [03 0b 0f];
+ qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ a0 b0 03 68 70 3b 92 a0 b0
+ 82 2b 50 10 30 02 22 30 0f];
+ qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,spm-cmd-wfi = [03 0b 0f];
+ qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ a0 b0 03 68 70 3b 92 a0 b0
+ 82 2b 50 10 30 02 22 30 0f];
+ qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,spm-cmd-wfi = [03 0b 0f];
+ qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ a0 b0 03 68 70 3b 92 a0 b0
+ 82 2b 50 10 30 02 22 30 0f];
+ qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ a0 b0 82 10 30 02 22 30 0f];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x1a>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
+ qcom,saw2-pmic-dly = <0x02020204>;
+ qcom,saw2-pmic-data0 = <0x0400009c>;
+ qcom,saw2-pmic-data1 = <0x00000060>;
+ qcom,saw2-pmic-data2 = <0x0000001c>;
+ qcom,saw2-pmic-data3 = <0x04000000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>; /* TODO: */
+ qcom,phase-port = <0x1>; /* TODO: */
+ qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
+ qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
+ 78 80 44 22 50 3b 60 02 32
+ 50 0f];
+ qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
+ 07 01 b0 78 80 12 44 a0 50
+ 3b 60 02 32 a0 50 0f];
+ };
+};
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3164281..076c609 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -243,6 +243,8 @@
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
select MSM_PIL
+ select MSM_SPM_V2
+ select MSM_L2_SPM
config ARCH_FSM9XXX
bool "FSM9XXX"
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 2a6294f..051d4de 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -21,6 +21,14 @@
#include "spm_driver.h"
+#define MSM_SPM_PMIC_STATE_IDLE 0
+
+#define SAW2_V1_VER_REG 0x04
+#define SAW2_V2_VER_REG 0xfd0
+
+#define SAW2_MAJOR_2 2
+
+
enum {
MSM_SPM_DEBUG_SHADOW = 1U << 0,
MSM_SPM_DEBUG_VCTL = 1U << 1,
@@ -31,35 +39,95 @@
debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
);
-#define MSM_SPM_PMIC_STATE_IDLE 0
+static uint32_t msm_spm_reg_offsets_v1[MSM_SPM_REG_NR] = {
+ [MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ [MSM_SPM_REG_SAW2_ID] = 0x04,
+ [MSM_SPM_REG_SAW2_CFG] = 0x08,
+ [MSM_SPM_REG_SAW2_STS0] = 0x0C,
+ [MSM_SPM_REG_SAW2_STS1] = 0x10,
+ [MSM_SPM_REG_SAW2_VCTL] = 0x14,
+ [MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
+ [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
+ [MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
+ [MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
+ [MSM_SPM_REG_SAW2_RST] = 0x30,
+ [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+};
-static uint32_t msm_spm_reg_offsets[MSM_SPM_REG_NR] = {
- [MSM_SPM_REG_SAW2_SECURE] = 0x00,
-
- [MSM_SPM_REG_SAW2_ID] = 0x04,
- [MSM_SPM_REG_SAW2_CFG] = 0x08,
- [MSM_SPM_REG_SAW2_STS0] = 0x0C,
- [MSM_SPM_REG_SAW2_STS1] = 0x10,
-
- [MSM_SPM_REG_SAW2_VCTL] = 0x14,
-
- [MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
- [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
-
- [MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
- [MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
- [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
- [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
- [MSM_SPM_REG_SAW2_RST] = 0x30,
-
- [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+static uint32_t msm_spm_reg_offsets_v2[MSM_SPM_REG_NR] = {
+ [MSM_SPM_REG_SAW2_SECURE] = 0x00,
+ [MSM_SPM_REG_SAW2_ID] = 0x04,
+ [MSM_SPM_REG_SAW2_CFG] = 0x08,
+ [MSM_SPM_REG_SAW2_SPM_STS] = 0x0C,
+ [MSM_SPM_REG_SAW2_AVS_STS] = 0x10,
+ [MSM_SPM_REG_SAW2_PMIC_STS] = 0x14,
+ [MSM_SPM_REG_SAW2_RST] = 0x18,
+ [MSM_SPM_REG_SAW2_VCTL] = 0x1C,
+ [MSM_SPM_REG_SAW2_AVS_CTL] = 0x20,
+ [MSM_SPM_REG_SAW2_AVS_LIMIT] = 0x24,
+ [MSM_SPM_REG_SAW2_AVS_DLY] = 0x28,
+ [MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x2C,
+ [MSM_SPM_REG_SAW2_SPM_CTL] = 0x30,
+ [MSM_SPM_REG_SAW2_SPM_DLY] = 0x34,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x40,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x44,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_2] = 0x48,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_3] = 0x4C,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_4] = 0x50,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_5] = 0x54,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_6] = 0x58,
+ [MSM_SPM_REG_SAW2_PMIC_DATA_7] = 0x5C,
+ [MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+ [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)
+{
+ return 32;
+}
+
+static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
+ unsigned int reg_index)
+{
+ __raw_writel(dev->reg_shadow[reg_index],
+ dev->reg_base_addr + dev->reg_offsets[reg_index]);
+}
+
+static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
+ unsigned int reg_index)
+{
+ dev->reg_shadow[reg_index] =
+ __raw_readl(dev->reg_base_addr +
+ dev->reg_offsets[reg_index]);
+}
+
+static inline void msm_spm_drv_set_start_addr(
+ struct msm_spm_driver_data *dev, uint32_t addr)
+{
+ addr &= 0x7F;
+ addr <<= 4;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
+}
+
+static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
+{
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
+
+ if (dev->major == SAW2_MAJOR_2)
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
+ else
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 18) & 0x1;
+}
+
static inline void msm_spm_drv_set_vctl(struct msm_spm_driver_data *dev,
uint32_t vlevel)
{
@@ -73,58 +141,81 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
}
-static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
+static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
+ uint32_t vlevel)
{
- __raw_writel(dev->reg_shadow[reg_index],
- dev->reg_base_addr + msm_spm_reg_offsets[reg_index]);
+ unsigned int pmic_data = 0;
+
+ pmic_data |= vlevel;
+ pmic_data |= (dev->vctl_port & 0x7) << 16;
+
+ dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0x700FF;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
}
-static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
+static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
+ unsigned int vlevel)
{
- dev->reg_shadow[reg_index] =
- __raw_readl(dev->reg_base_addr +
- msm_spm_reg_offsets[reg_index]);
-}
-
-static inline uint32_t msm_spm_drv_get_awake_vlevel(
- struct msm_spm_driver_data *dev)
-{
- return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] & 0xFF;
+ if (dev->major == SAW2_MAJOR_2)
+ return msm_spm_drv_set_vctl2(dev, vlevel);
+ else
+ return msm_spm_drv_set_vctl(dev, vlevel);
}
static inline uint32_t msm_spm_drv_get_sts_pmic_state(
struct msm_spm_driver_data *dev)
{
- return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+ if (dev->major == SAW2_MAJOR_2) {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
+ 0x03;
+ } else {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
+ return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+ }
}
static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
struct msm_spm_driver_data *dev)
{
- return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+ if (dev->major == SAW2_MAJOR_2) {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+ return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
+ } else {
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
+ return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+ }
}
-static inline uint32_t msm_spm_drv_get_num_spm_entry(
- struct msm_spm_driver_data *dev)
+static inline uint32_t msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
+ uint32_t *major, uint32_t *minor)
{
- return 32;
-}
+ int ret = -ENODEV;
+ uint32_t val = 0;
-static inline void msm_spm_drv_set_start_addr(
- struct msm_spm_driver_data *dev, uint32_t addr)
-{
- addr &= 0x7F;
- addr <<= 4;
- dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
- dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
-}
+ msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_VERSION);
+ val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
+ if (dev->ver_reg == SAW2_V2_VER_REG) {
+ *major = (val >> 28) & 0xF;
+ *minor = (val >> 16) & 0xFFF;
+ ret = 0;
+ } else if (dev->ver_reg == SAW2_V1_VER_REG) {
+ *major = (val >> 4) & 0xF;
+ *minor = val & 0xF;
+ ret = 0;
+ }
+
+ return ret;
+}
/******************************************************************************
* Public functions
*****************************************************************************/
+
inline int msm_spm_drv_set_spm_enable(
struct msm_spm_driver_data *dev, bool enable)
{
@@ -156,48 +247,42 @@
for (i = 0; i < num_spm_entry; i++) {
__raw_writel(dev->reg_seq_entry_shadow[i],
dev->reg_base_addr
- + msm_spm_reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+ + dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+ 4 * i);
}
mb();
}
int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
- uint8_t *cmd, uint32_t offset)
+ uint8_t *cmd, uint32_t *offset)
{
- uint32_t offset_w = offset / 4;
- int ret = 0;
+ uint32_t cmd_w;
+ uint32_t offset_w = *offset / 4;
+ uint8_t last_cmd;
- if (!cmd || !dev) {
- __WARN();
- goto failed_write_seq_data;
- };
+ if (!cmd)
+ return -EINVAL;
while (1) {
int i;
- uint32_t cmd_w = 0;
- uint8_t last_cmd = 0;
+ cmd_w = 0;
+ last_cmd = 0;
+ cmd_w = dev->reg_seq_entry_shadow[offset_w];
- for (i = 0; i < 4; i++) {
- last_cmd = (last_cmd == 0x0f) ? 0x0f : *(cmd + i);
- cmd_w |= last_cmd << (i * 8);
- ret++;
+ for (i = (*offset % 4) ; i < 4; i++) {
+ last_cmd = *(cmd++);
+ cmd_w |= last_cmd << (i * 8);
+ (*offset)++;
+ if (last_cmd == 0x0f)
+ break;
}
- if (offset_w >= msm_spm_drv_get_num_spm_entry(dev)) {
- __WARN();
- goto failed_write_seq_data;
- }
-
- cmd += i;
dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
if (last_cmd == 0x0f)
break;
}
- return ret;
-failed_write_seq_data:
- return -EINVAL;
+ return 0;
}
int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
@@ -218,7 +303,7 @@
int i;
for (i = 0; i < MSM_SPM_REG_NR; i++)
pr_info("%s: reg %02x = 0x%08x\n", __func__,
- msm_spm_reg_offsets[i], dev->reg_shadow[i]);
+ dev->reg_offsets[i], dev->reg_shadow[i]);
}
return 0;
@@ -231,11 +316,14 @@
if (!dev)
return -EINVAL;
+ if (!msm_spm_pmic_arb_present(dev))
+ return -ENOSYS;
+
if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
pr_info("%s: requesting vlevel 0x%x\n",
__func__, vlevel);
- msm_spm_drv_set_vctl(dev, vlevel);
+ msm_spm_drv_apcs_set_vctl(dev, vlevel);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
@@ -243,7 +331,6 @@
/* Wait for PMIC state to return to idle or until timeout */
timeout_us = dev->vctl_timeout_us;
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
if (!timeout_us)
goto set_vdd_bail;
@@ -255,11 +342,8 @@
udelay(timeout_us);
timeout_us = 0;
}
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
}
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
-
if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
goto set_vdd_bail;
@@ -275,6 +359,54 @@
return -EIO;
}
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+ unsigned int phase_cnt)
+{
+ unsigned int pmic_data = 0;
+ unsigned int timeout_us = 0;
+
+ if (dev->major != SAW2_MAJOR_2)
+ return -ENODEV;
+
+ pmic_data |= phase_cnt & 0xFF;
+ pmic_data |= (dev->phase_port & 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;
+
+ if (timeout_us > 10) {
+ udelay(10);
+ timeout_us -= 10;
+ } else {
+ udelay(timeout_us);
+ timeout_us = 0;
+ }
+ }
+
+ 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)
{
int i;
@@ -289,12 +421,18 @@
int __init msm_spm_drv_init(struct msm_spm_driver_data *dev,
struct msm_spm_platform_data *data)
{
-
int i;
int num_spm_entry;
BUG_ON(!dev || !data);
+ if (dev->ver_reg == SAW2_V2_VER_REG)
+ dev->reg_offsets = msm_spm_reg_offsets_v2;
+ else
+ dev->reg_offsets = msm_spm_reg_offsets_v1;
+
+ dev->vctl_port = data->vctl_port;
+ dev->phase_port = data->phase_port;
dev->reg_base_addr = data->reg_base_addr;
memcpy(dev->reg_shadow, data->reg_init_values,
sizeof(data->reg_init_values));
@@ -314,18 +452,16 @@
/* barrier to ensure read completes before we proceed further*/
mb();
+ msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
+
num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
dev->reg_seq_entry_shadow =
- kmalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
+ kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
GFP_KERNEL);
if (!dev->reg_seq_entry_shadow)
return -ENOMEM;
-
- memset(dev->reg_seq_entry_shadow, 0x0f,
- num_spm_entry * sizeof(*dev->reg_seq_entry_shadow));
-
return 0;
}
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 21c7dca..154303b 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -70,19 +70,33 @@
MSM_SPM_REG_SAW2_AVS_HYSTERESIS,
MSM_SPM_REG_SAW2_SPM_CTL,
MSM_SPM_REG_SAW2_PMIC_DLY,
+ MSM_SPM_REG_SAW2_AVS_LIMIT,
+ MSM_SPM_REG_SAW2_AVS_DLY,
+ MSM_SPM_REG_SAW2_SPM_DLY,
MSM_SPM_REG_SAW2_PMIC_DATA_0,
MSM_SPM_REG_SAW2_PMIC_DATA_1,
+ MSM_SPM_REG_SAW2_PMIC_DATA_2,
+ MSM_SPM_REG_SAW2_PMIC_DATA_3,
+ MSM_SPM_REG_SAW2_PMIC_DATA_4,
+ MSM_SPM_REG_SAW2_PMIC_DATA_5,
+ MSM_SPM_REG_SAW2_PMIC_DATA_6,
+ MSM_SPM_REG_SAW2_PMIC_DATA_7,
MSM_SPM_REG_SAW2_RST,
MSM_SPM_REG_NR_INITIALIZE = MSM_SPM_REG_SAW2_RST,
+
MSM_SPM_REG_SAW2_ID,
MSM_SPM_REG_SAW2_SECURE,
MSM_SPM_REG_SAW2_STS0,
MSM_SPM_REG_SAW2_STS1,
MSM_SPM_REG_SAW2_VCTL,
- MSM_SPM_REG_SAW2_SEQ_ENTRY ,
+ MSM_SPM_REG_SAW2_SEQ_ENTRY,
+ MSM_SPM_REG_SAW2_SPM_STS,
+ MSM_SPM_REG_SAW2_AVS_STS,
+ MSM_SPM_REG_SAW2_PMIC_STS,
+ MSM_SPM_REG_SAW2_VERSION,
- MSM_SPM_REG_NR
+ MSM_SPM_REG_NR,
};
struct msm_spm_seq_entry {
@@ -95,8 +109,13 @@
void __iomem *reg_base_addr;
uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
+ uint32_t ver_reg;
+ uint32_t vctl_port;
+ uint32_t phase_port;
+
uint8_t awake_vlevel;
uint32_t vctl_timeout_us;
+ uint32_t avs_timeout_us;
uint32_t num_modes;
struct msm_spm_seq_entry *modes;
@@ -105,18 +124,93 @@
#if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
+/* Public functions */
+
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
+
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ */
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
-void msm_spm_reinit(void);
-void msm_spm_allow_x_cpu_set_vdd(bool allowed);
-int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
+ * @cpu: core id
+ */
int msm_spm_turn_on_cpu_rail(unsigned int cpu);
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_allow_x_cpu_set_vdd(): Turn on/off cross calling to set voltage
+ * @allowed: boolean to indicate on/off.
+ */
+void msm_spm_allow_x_cpu_set_vdd(bool allowed);
+
+/**
+ * msm_spm_reinit(): Reinitialize SPM registers
+ */
+void msm_spm_reinit(void);
+
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
+int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * msm_spm_device_init(): Device tree initialization function
+ */
+int msm_spm_device_init(void);
+
#if defined(CONFIG_MSM_L2_SPM)
+
+/* Public functions */
+
+/**
+ * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
+ * for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
+
+/**
+ * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
+ * @vlevel: Encoded PMIC data.
+ */
+int msm_spm_apcs_set_vdd(unsigned int vlevel);
+
+/**
+ * msm_spm_apcs_set_phase(): Set number of SMPS phases.
+ * phase_cnt: Number of phases to be set active
+ */
+int msm_spm_apcs_set_phase(unsigned int phase_cnt);
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_l2_init(): Board initialization function
+ * @data: SPM target specific register configuration
+ */
int msm_spm_l2_init(struct msm_spm_platform_data *data);
+
+/**
+ * msm_spm_l2_reinit(): Reinitialize L2 SPM registers
+ */
void msm_spm_l2_reinit(void);
+
#else
+
static inline int msm_spm_l2_set_low_power_mode(unsigned int mode,
bool notify_rpm)
{
@@ -130,10 +224,18 @@
{
/* empty */
}
+
+static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+ return -ENOSYS;
+}
+
+static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+ return -ENOSYS;
+}
#endif /* defined(CONFIG_MSM_L2_SPM) */
-
#else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
-
static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
{
return -ENOSYS;
@@ -158,6 +260,11 @@
{
return -ENOSYS;
}
-#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
+static inline int msm_spm_device_init(void)
+{
+ return -ENOSYS;
+}
+
+#endif /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
#endif /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2b17fa3..838ec55 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -17,6 +17,9 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include "spm.h"
@@ -35,6 +38,7 @@
uint32_t num_modes;
};
+static struct msm_spm_device msm_spm_l2_device;
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
static atomic_t msm_spm_set_vdd_x_cpu_allowed = ATOMIC_INIT(1);
@@ -42,6 +46,7 @@
{
atomic_set(&msm_spm_set_vdd_x_cpu_allowed, allowed ? 1 : 0);
}
+EXPORT_SYMBOL(msm_spm_allow_x_cpu_set_vdd);
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
{
@@ -62,6 +67,7 @@
local_irq_restore(flags);
return ret;
}
+EXPORT_SYMBOL(msm_spm_set_vdd);
static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
unsigned int mode, bool notify_rpm)
@@ -100,6 +106,7 @@
if (!dev->modes)
goto spm_failed_malloc;
+ dev->reg_data.ver_reg = data->ver_reg;
ret = msm_spm_drv_init(&dev->reg_data, data);
if (ret)
@@ -107,15 +114,17 @@
for (i = 0; i < dev->num_modes; i++) {
+ /* Default offset is 0 and gets updated as we write more
+ * sequences into SPM
+ */
+ dev->modes[i].start_addr = offset;
ret = msm_spm_drv_write_seq_data(&dev->reg_data,
- data->modes[i].cmd, offset);
+ data->modes[i].cmd, &offset);
if (ret < 0)
goto spm_failed_init;
dev->modes[i].mode = data->modes[i].mode;
dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
- dev->modes[i].start_addr = offset;
- offset += ret;
}
msm_spm_drv_flush_seq_entry(&dev->reg_data);
return 0;
@@ -126,39 +135,6 @@
return ret;
}
-void msm_spm_reinit(void)
-{
- unsigned int cpu;
- for_each_possible_cpu(cpu)
- msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
-}
-
-int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
-{
- struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
- return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
-}
-
-int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
-{
- unsigned int cpu;
- int ret = 0;
-
- BUG_ON((nr_devs < num_possible_cpus()) || !data);
-
- for_each_possible_cpu(cpu) {
- struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
- ret = msm_spm_dev_init(dev, &data[cpu]);
- if (ret < 0) {
- pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
- cpu, ret);
- break;
- }
- }
-
- return ret;
-}
-
int msm_spm_turn_on_cpu_rail(unsigned int cpu)
{
uint32_t val = 0;
@@ -192,22 +168,227 @@
}
EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
-#if defined(CONFIG_MSM_L2_SPM)
-static struct msm_spm_device msm_spm_l2_device;
+void msm_spm_reinit(void)
+{
+ unsigned int cpu;
+ for_each_possible_cpu(cpu)
+ msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
+}
+EXPORT_SYMBOL(msm_spm_reinit);
+
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+ struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
+ return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
+}
+EXPORT_SYMBOL(msm_spm_set_low_power_mode);
+
+/* Board file init function */
+int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
+{
+ unsigned int cpu;
+ int ret = 0;
+
+ BUG_ON((nr_devs < num_possible_cpus()) || !data);
+
+ for_each_possible_cpu(cpu) {
+ struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
+ ret = msm_spm_dev_init(dev, &data[cpu]);
+ if (ret < 0) {
+ pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
+ cpu, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_MSM_L2_SPM
int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
{
return msm_spm_dev_set_low_power_mode(
&msm_spm_l2_device, mode, notify_rpm);
}
-
-int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
-{
- return msm_spm_dev_init(&msm_spm_l2_device, data);
-}
+EXPORT_SYMBOL(msm_spm_l2_set_low_power_mode);
void msm_spm_l2_reinit(void)
{
msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
}
+EXPORT_SYMBOL(msm_spm_l2_reinit);
+
+int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+ return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
+
+int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+ return msm_spm_drv_set_phase(&msm_spm_l2_device.reg_data, phase_cnt);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_phase);
+
+/* Board file init function */
+int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
+{
+ return msm_spm_dev_init(&msm_spm_l2_device, data);
+}
#endif
+
+static int __devinit msm_spm_dev_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int cpu = 0;
+ int i = 0;
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_spm_platform_data spm_data;
+ char *key = NULL;
+ uint32_t val = 0;
+ struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
+ size_t len = 0;
+ struct msm_spm_device *dev = NULL;
+ struct resource *res = NULL;
+ uint32_t mode_count = 0;
+
+ struct spm_of {
+ char *key;
+ uint32_t id;
+ };
+
+ struct spm_of spm_of_data[] = {
+ {"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
+ {"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
+ {"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
+ {"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
+ {"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
+ {"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+ {"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+ {"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
+ {"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
+ {"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
+ {"qcom,saw2-pmic-data3", MSM_SPM_REG_SAW2_PMIC_DATA_3},
+ {"qcom,saw2-pmic-data4", MSM_SPM_REG_SAW2_PMIC_DATA_4},
+ {"qcom,saw2-pmic-data5", MSM_SPM_REG_SAW2_PMIC_DATA_5},
+ {"qcom,saw2-pmic-data6", MSM_SPM_REG_SAW2_PMIC_DATA_6},
+ {"qcom,saw2-pmic-data7", MSM_SPM_REG_SAW2_PMIC_DATA_7},
+ };
+
+ struct mode_of {
+ char *key;
+ uint32_t id;
+ uint32_t notify_rpm;
+ };
+
+ struct mode_of mode_of_data[] = {
+ {"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+ {"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+ {"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+ {"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+ };
+
+ BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+ memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+ memset(&modes, 0,
+ (MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto fail;
+
+ spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!spm_data.reg_base_addr)
+ return -ENOMEM;
+
+ key = "qcom,core-id";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ cpu = val;
+
+ key = "qcom,saw2-ver-reg";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ spm_data.ver_reg = val;
+
+ key = "qcom,vctl-timeout-us";
+ ret = of_property_read_u32(node, key, &val);
+ if (!ret)
+ spm_data.vctl_timeout_us = val;
+
+ /* optional */
+ key = "qcom,vctl-port";
+ ret = of_property_read_u32(node, key, &val);
+ if (!ret)
+ spm_data.vctl_port = val;
+
+ /* optional */
+ key = "qcom,phase-port";
+ ret = of_property_read_u32(node, key, &val);
+ if (!ret)
+ spm_data.phase_port = val;
+
+ for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
+ ret = of_property_read_u32(node, spm_of_data[i].key, &val);
+ if (ret)
+ continue;
+ spm_data.reg_init_values[spm_of_data[i].id] = val;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+ key = mode_of_data[i].key;
+ modes[mode_count].cmd =
+ (uint8_t *)of_get_property(node, key, &len);
+ if (!modes[mode_count].cmd)
+ continue;
+ modes[mode_count].mode = mode_of_data[i].id;
+ modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
+ mode_count++;
+ }
+
+ spm_data.modes = modes;
+ spm_data.num_modes = mode_count;
+
+ /*
+ * Device with id 0..NR_CPUS are SPM for apps cores
+ * Device with id 0xFFFF is for L2 SPM.
+ */
+ if (cpu >= 0 && cpu < num_possible_cpus())
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+ else
+ dev = &msm_spm_l2_device;
+
+ ret = msm_spm_dev_init(dev, &spm_data);
+ if (ret < 0)
+ pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
+
+ return ret;
+
+fail:
+ pr_err("%s: Failed reading node=%s, key=%s\n",
+ __func__, node->full_name, key);
+ return -EFAULT;
+}
+
+static struct of_device_id msm_spm_match_table[] = {
+ {.compatible = "qcom,spm-v2"},
+ {},
+};
+
+static struct platform_driver msm_spm_device_driver = {
+ .probe = msm_spm_dev_probe,
+ .driver = {
+ .name = "spm-v2",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_spm_match_table,
+ },
+};
+
+int __init msm_spm_device_init(void)
+{
+ return platform_driver_register(&msm_spm_device_driver);
+}
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index 712f051..f272adb 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -15,10 +15,17 @@
#include "spm.h"
struct msm_spm_driver_data {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t ver_reg;
+ uint32_t vctl_port;
+ uint32_t phase_port;
void __iomem *reg_base_addr;
uint32_t vctl_timeout_us;
+ uint32_t avs_timeout_us;
uint32_t reg_shadow[MSM_SPM_REG_NR];
uint32_t *reg_seq_entry_shadow;
+ uint32_t *reg_offsets;
};
int msm_spm_drv_init(struct msm_spm_driver_data *dev,
@@ -29,9 +36,10 @@
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
unsigned int vlevel);
int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
- uint8_t *cmd, uint32_t offset);
+ uint8_t *cmd, uint32_t *offset);
void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
int msm_spm_drv_set_spm_enable(struct msm_spm_driver_data *dev,
bool enable);
-
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+ unsigned int phase_cnt);
#endif