Merge "msm: spm: Add cross-calling support to change voltages"
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 05d11d2..b87b0f1 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -38,16 +38,38 @@
 	uint32_t num_modes;
 };
 
+struct msm_spm_vdd_info {
+	uint32_t cpu;
+	uint32_t vlevel;
+	int err;
+};
+
 static struct msm_spm_device msm_spm_l2_device;
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
 
-int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+
+/* Must be called on the same cpu as the one being set to */
+static void msm_spm_smp_set_vdd(void *data)
 {
 	struct msm_spm_device *dev;
-	int ret = -EIO;
+	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
 
-	dev = &per_cpu(msm_cpu_spm_device, cpu);
-	ret = msm_spm_drv_set_vdd(&dev->reg_data, vlevel);
+	dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+}
+
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	struct msm_spm_vdd_info info;
+	int ret;
+
+	info.cpu = cpu;
+	info.vlevel = vlevel;
+
+	/* Set to true to block on vdd change */
+	ret = smp_call_function_single(cpu, msm_spm_smp_set_vdd, &info, true);
+	if (!ret)
+		ret = info.err;
 
 	return ret;
 }