blob: 3ac1348a4a9acbe3fa31c3a937a1bfa1f91becd4 [file] [log] [blame]
Anji Jonnala5063e042013-03-09 09:49:11 +05301/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/io.h>
19#include <linux/slab.h>
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060020#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <mach/msm_iomap.h>
Praveen Chidambaram76679d42011-12-16 14:19:02 -070024#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include "spm.h"
26#include "spm_driver.h"
27
28struct msm_spm_power_modes {
29 uint32_t mode;
30 bool notify_rpm;
31 uint32_t start_addr;
32
33};
34
35struct msm_spm_device {
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -060036 bool initialized;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037 struct msm_spm_driver_data reg_data;
38 struct msm_spm_power_modes *modes;
39 uint32_t num_modes;
Anji Jonnala5063e042013-03-09 09:49:11 +053040 uint32_t cpu_vdd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041};
42
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060043struct msm_spm_vdd_info {
44 uint32_t cpu;
45 uint32_t vlevel;
46 int err;
47};
48
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -060049static struct msm_spm_device msm_spm_l2_device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
Praveen Chidambaram48197dd2013-03-21 15:51:43 -060051static bool msm_spm_L2_apcs_master;
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060052
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060053static void msm_spm_smp_set_vdd(void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055 struct msm_spm_device *dev;
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060056 struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057
Praveen Chidambaram48197dd2013-03-21 15:51:43 -060058 if (msm_spm_L2_apcs_master)
59 dev = &msm_spm_l2_device;
60 else
61 dev = &per_cpu(msm_cpu_spm_device, info->cpu);
62
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -060063 if (!dev->initialized)
64 return;
Praveen Chidambaram48197dd2013-03-21 15:51:43 -060065
66 if (msm_spm_L2_apcs_master)
67 get_cpu();
68
Anji Jonnala5063e042013-03-09 09:49:11 +053069 dev->cpu_vdd = info->vlevel;
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060070 info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
Praveen Chidambaram48197dd2013-03-21 15:51:43 -060071
72 if (msm_spm_L2_apcs_master)
73 put_cpu();
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060074}
75
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -060076/**
77 * msm_spm_set_vdd(): Set core voltage
78 * @cpu: core id
79 * @vlevel: Encoded PMIC data.
80 */
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060081int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
82{
83 struct msm_spm_vdd_info info;
84 int ret;
85
86 info.cpu = cpu;
87 info.vlevel = vlevel;
Mahesh Sivasubramanian072b2922013-04-16 15:36:54 -060088 info.err = -ENODEV;
Praveen Chidambarambcd483b2012-09-16 14:54:35 -060089
Praveen Chidambaram48197dd2013-03-21 15:51:43 -060090 if (!msm_spm_L2_apcs_master && (smp_processor_id() != cpu) &&
91 cpu_online(cpu)) {
Praveen Chidambaram8624ce72012-10-05 17:11:33 -060092 /**
93 * We do not want to set the voltage of another core from
94 * this core, as its possible that we may race the vdd change
95 * with the SPM state machine of that core, which could also
96 * be changing the voltage of that core during power collapse.
97 * Hence, set the function to be executed on that core and block
98 * until the vdd change is complete.
99 */
100 ret = smp_call_function_single(cpu, msm_spm_smp_set_vdd,
101 &info, true);
102 if (!ret)
103 ret = info.err;
104 } else {
105 /**
106 * Since the core is not online, it is safe to set the vdd
107 * directly.
108 */
109 msm_spm_smp_set_vdd(&info);
Praveen Chidambarambcd483b2012-09-16 14:54:35 -0600110 ret = info.err;
Praveen Chidambaram8624ce72012-10-05 17:11:33 -0600111 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700113 return ret;
114}
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600115EXPORT_SYMBOL(msm_spm_set_vdd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600117/**
118 * msm_spm_get_vdd(): Get core voltage
119 * @cpu: core id
120 * @return: Returns encoded PMIC data.
121 */
Praveen Chidambaram4133ba12012-09-29 22:27:03 -0600122unsigned int msm_spm_get_vdd(unsigned int cpu)
123{
124 struct msm_spm_device *dev;
125
Praveen Chidambaram48197dd2013-03-21 15:51:43 -0600126 if (msm_spm_L2_apcs_master)
127 dev = &msm_spm_l2_device;
128 else
129 dev = &per_cpu(msm_cpu_spm_device, cpu);
Anji Jonnala5063e042013-03-09 09:49:11 +0530130 return dev->cpu_vdd;
Praveen Chidambaram4133ba12012-09-29 22:27:03 -0600131}
132EXPORT_SYMBOL(msm_spm_get_vdd);
133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
135 unsigned int mode, bool notify_rpm)
136{
137 uint32_t i;
138 uint32_t start_addr = 0;
139 int ret = -EINVAL;
140
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -0600141 if (!dev->initialized)
142 return -ENXIO;
143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 if (mode == MSM_SPM_MODE_DISABLED) {
145 ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
146 } else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
147 for (i = 0; i < dev->num_modes; i++) {
148 if ((dev->modes[i].mode == mode) &&
149 (dev->modes[i].notify_rpm == notify_rpm)) {
150 start_addr = dev->modes[i].start_addr;
151 break;
152 }
153 }
154 ret = msm_spm_drv_set_low_power_mode(&dev->reg_data,
155 start_addr);
156 }
157 return ret;
158}
159
Stephen Boyddb354112012-05-09 14:24:58 -0700160static int __devinit msm_spm_dev_init(struct msm_spm_device *dev,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 struct msm_spm_platform_data *data)
162{
163 int i, ret = -ENOMEM;
164 uint32_t offset = 0;
165
166 dev->num_modes = data->num_modes;
167 dev->modes = kmalloc(
168 sizeof(struct msm_spm_power_modes) * dev->num_modes,
169 GFP_KERNEL);
170
171 if (!dev->modes)
172 goto spm_failed_malloc;
173
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600174 dev->reg_data.ver_reg = data->ver_reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 ret = msm_spm_drv_init(&dev->reg_data, data);
176
177 if (ret)
178 goto spm_failed_init;
179
180 for (i = 0; i < dev->num_modes; i++) {
181
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600182 /* Default offset is 0 and gets updated as we write more
183 * sequences into SPM
184 */
185 dev->modes[i].start_addr = offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 ret = msm_spm_drv_write_seq_data(&dev->reg_data,
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600187 data->modes[i].cmd, &offset);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 if (ret < 0)
189 goto spm_failed_init;
190
191 dev->modes[i].mode = data->modes[i].mode;
192 dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 }
194 msm_spm_drv_flush_seq_entry(&dev->reg_data);
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -0600195 dev->initialized = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 return 0;
197
198spm_failed_init:
199 kfree(dev->modes);
200spm_failed_malloc:
201 return ret;
202}
203
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600204/**
205 * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
206 * @cpu: core id
207 */
Praveen Chidambaramc0750ca2012-01-08 10:03:28 -0700208int msm_spm_turn_on_cpu_rail(unsigned int cpu)
209{
210 uint32_t val = 0;
211 uint32_t timeout = 0;
212 void *reg = NULL;
Stepan Moskovchenko2b0b06e2012-02-03 15:03:52 -0800213 void *saw_bases[] = {
214 0,
215 MSM_SAW1_BASE,
216 MSM_SAW2_BASE,
217 MSM_SAW3_BASE
218 };
Praveen Chidambaramc0750ca2012-01-08 10:03:28 -0700219
Stepan Moskovchenko2b0b06e2012-02-03 15:03:52 -0800220 if (cpu == 0 || cpu >= num_possible_cpus())
Praveen Chidambaramc0750ca2012-01-08 10:03:28 -0700221 return -EINVAL;
222
Stepan Moskovchenko2b0b06e2012-02-03 15:03:52 -0800223 reg = saw_bases[cpu];
Praveen Chidambaramc0750ca2012-01-08 10:03:28 -0700224
Stepan Moskovchenko5b9e7762012-09-21 20:32:17 -0700225 if (soc_class_is_msm8960() || soc_class_is_msm8930() ||
226 soc_class_is_apq8064()) {
Stepan Moskovchenko2b0b06e2012-02-03 15:03:52 -0800227 val = 0xA4;
228 reg += 0x14;
229 timeout = 512;
Praveen Chidambaramc0750ca2012-01-08 10:03:28 -0700230 } else {
231 return -ENOSYS;
232 }
233
234 writel_relaxed(val, reg);
235 mb();
236 udelay(timeout);
237
238 return 0;
239}
240EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
241
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600242void msm_spm_reinit(void)
243{
244 unsigned int cpu;
245 for_each_possible_cpu(cpu)
246 msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
247}
248EXPORT_SYMBOL(msm_spm_reinit);
249
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600250/**
251 * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
252 * @mode: SPM LPM mode to enter
253 * @notify_rpm: Notify RPM in this mode
254 */
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600255int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
256{
257 struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
258 return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
259}
260EXPORT_SYMBOL(msm_spm_set_low_power_mode);
261
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600262/**
263 * msm_spm_init(): Board initalization function
264 * @data: platform specific SPM register configuration data
265 * @nr_devs: Number of SPM devices being initialized
266 */
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600267int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
268{
269 unsigned int cpu;
270 int ret = 0;
271
272 BUG_ON((nr_devs < num_possible_cpus()) || !data);
273
274 for_each_possible_cpu(cpu) {
275 struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
276 ret = msm_spm_dev_init(dev, &data[cpu]);
277 if (ret < 0) {
278 pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
279 cpu, ret);
280 break;
281 }
282 }
283
284 return ret;
285}
286
287#ifdef CONFIG_MSM_L2_SPM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600289/**
290 * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
291 * for low power mode
292 * @mode: SPM LPM mode to enter
293 * @notify_rpm: Notify RPM in this mode
294 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
296{
297 return msm_spm_dev_set_low_power_mode(
298 &msm_spm_l2_device, mode, notify_rpm);
299}
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600300EXPORT_SYMBOL(msm_spm_l2_set_low_power_mode);
Maheshkumar Sivasubramanian4ac23762011-11-02 10:03:06 -0600301
302void msm_spm_l2_reinit(void)
303{
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -0600304 if (!msm_spm_l2_device.initialized)
305 return;
Maheshkumar Sivasubramanian4ac23762011-11-02 10:03:06 -0600306 msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
307}
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600308EXPORT_SYMBOL(msm_spm_l2_reinit);
309
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600310/**
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600311 * msm_spm_apcs_set_phase(): Set number of SMPS phases.
312 * phase_cnt: Number of phases to be set active
313 */
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600314int msm_spm_apcs_set_phase(unsigned int phase_cnt)
315{
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -0600316 if (!msm_spm_l2_device.initialized)
317 return -ENXIO;
Praveen Chidambaram1dbe4952012-10-03 17:06:02 -0600318 return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
319 MSM_SPM_PMIC_PHASE_PORT, phase_cnt);
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600320}
321EXPORT_SYMBOL(msm_spm_apcs_set_phase);
322
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600323/** msm_spm_enable_fts_lpm() : Enable FTS to switch to low power
324 * when the cores are in low power modes
325 * @mode: The mode configuration for FTS
326 */
Praveen Chidambaram1dbe4952012-10-03 17:06:02 -0600327int msm_spm_enable_fts_lpm(uint32_t mode)
328{
Mahesh Sivasubramanianbc420242013-03-26 17:18:04 -0600329 if (!msm_spm_l2_device.initialized)
330 return -ENXIO;
Praveen Chidambaram1dbe4952012-10-03 17:06:02 -0600331 return msm_spm_drv_set_pmic_data(&msm_spm_l2_device.reg_data,
332 MSM_SPM_PMIC_PFM_PORT, mode);
333}
334EXPORT_SYMBOL(msm_spm_enable_fts_lpm);
335
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600336/**
337 * msm_spm_l2_init(): Board initialization function
338 * @data: SPM target specific register configuration
339 */
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600340int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
341{
342 return msm_spm_dev_init(&msm_spm_l2_device, data);
343}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344#endif
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600345
Sathish Ambley86487e52012-06-11 13:46:11 -0700346static int __devinit msm_spm_dev_probe(struct platform_device *pdev)
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600347{
348 int ret = 0;
349 int cpu = 0;
350 int i = 0;
351 struct device_node *node = pdev->dev.of_node;
352 struct msm_spm_platform_data spm_data;
353 char *key = NULL;
354 uint32_t val = 0;
355 struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
356 size_t len = 0;
357 struct msm_spm_device *dev = NULL;
358 struct resource *res = NULL;
359 uint32_t mode_count = 0;
360
361 struct spm_of {
362 char *key;
363 uint32_t id;
364 };
365
366 struct spm_of spm_of_data[] = {
367 {"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
368 {"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
369 {"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600370 {"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
Praveen Chidambaram2772d832012-08-22 11:50:34 -0600371 {"qcom,saw2-avs-dly", MSM_SPM_REG_SAW2_AVS_DLY},
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600372 {"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
Praveen Chidambaram2772d832012-08-22 11:50:34 -0600373 {"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600374 {"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
375 {"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
376 {"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
377 {"qcom,saw2-pmic-data3", MSM_SPM_REG_SAW2_PMIC_DATA_3},
378 {"qcom,saw2-pmic-data4", MSM_SPM_REG_SAW2_PMIC_DATA_4},
379 {"qcom,saw2-pmic-data5", MSM_SPM_REG_SAW2_PMIC_DATA_5},
380 {"qcom,saw2-pmic-data6", MSM_SPM_REG_SAW2_PMIC_DATA_6},
381 {"qcom,saw2-pmic-data7", MSM_SPM_REG_SAW2_PMIC_DATA_7},
382 };
383
384 struct mode_of {
385 char *key;
386 uint32_t id;
387 uint32_t notify_rpm;
388 };
389
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600390 struct mode_of of_cpu_modes[] = {
391 {"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
392 {"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
393 {"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
394 {"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600395 };
396
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600397 struct mode_of of_l2_modes[] = {
Girish Mahadevanee035b92013-04-11 10:49:50 -0600398 {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600399 {"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
400 {"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
401 };
402
403 struct mode_of *mode_of_data;
404 int num_modes;
405
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600406 memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
407 memset(&modes, 0,
408 (MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
409
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600410 key = "qcom,core-id";
411 ret = of_property_read_u32(node, key, &val);
412 if (ret)
413 goto fail;
414 cpu = val;
415
Priyanka Mathure74a78d2013-04-25 14:34:32 -0700416 /*
417 * Device with id 0..NR_CPUS are SPM for apps cores
418 * Device with id 0xFFFF is for L2 SPM.
419 */
420 if (cpu >= 0 && cpu < num_possible_cpus()) {
421 mode_of_data = of_cpu_modes;
422 num_modes = ARRAY_SIZE(of_cpu_modes);
423 dev = &per_cpu(msm_cpu_spm_device, cpu);
424
425 } else if (cpu == 0xffff) {
426 mode_of_data = of_l2_modes;
427 num_modes = ARRAY_SIZE(of_l2_modes);
428 dev = &msm_spm_l2_device;
429 } else
430 return ret;
431
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600432 key = "qcom,saw2-ver-reg";
433 ret = of_property_read_u32(node, key, &val);
434 if (ret)
435 goto fail;
436 spm_data.ver_reg = val;
437
438 key = "qcom,vctl-timeout-us";
439 ret = of_property_read_u32(node, key, &val);
440 if (!ret)
441 spm_data.vctl_timeout_us = val;
Priyanka Mathure74a78d2013-04-25 14:34:32 -0700442 else if (cpu == 0xffff)
443 goto fail;
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600444
Priyanka Mathure74a78d2013-04-25 14:34:32 -0700445 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
446 if (!res)
447 goto fail;
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600448
Priyanka Mathure74a78d2013-04-25 14:34:32 -0700449 spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
450 resource_size(res));
451 if (!spm_data.reg_base_addr)
452 return -ENOMEM;
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600453
Praveen Chidambaram1dbe4952012-10-03 17:06:02 -0600454 spm_data.vctl_port = -1;
455 spm_data.phase_port = -1;
456 spm_data.pfm_port = -1;
457
458 /* optional */
459 if (dev == &msm_spm_l2_device) {
460 key = "qcom,vctl-port";
461 ret = of_property_read_u32(node, key, &val);
462 if (!ret)
463 spm_data.vctl_port = val;
464
465 key = "qcom,phase-port";
466 ret = of_property_read_u32(node, key, &val);
467 if (!ret)
468 spm_data.phase_port = val;
469
470 key = "qcom,pfm-port";
471 ret = of_property_read_u32(node, key, &val);
472 if (!ret)
473 spm_data.pfm_port = val;
Praveen Chidambaram48197dd2013-03-21 15:51:43 -0600474
475 key = "qcom,L2-spm-is-apcs-master";
476 msm_spm_L2_apcs_master =
477 of_property_read_bool(pdev->dev.of_node, key);
Praveen Chidambaram1dbe4952012-10-03 17:06:02 -0600478 }
479
480 for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
481 ret = of_property_read_u32(node, spm_of_data[i].key, &val);
482 if (ret)
483 continue;
484 spm_data.reg_init_values[spm_of_data[i].id] = val;
485 }
486
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600487 for (i = 0; i < num_modes; i++) {
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600488 key = mode_of_data[i].key;
489 modes[mode_count].cmd =
490 (uint8_t *)of_get_property(node, key, &len);
491 if (!modes[mode_count].cmd)
492 continue;
493 modes[mode_count].mode = mode_of_data[i].id;
494 modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
495 mode_count++;
496 }
497
498 spm_data.modes = modes;
499 spm_data.num_modes = mode_count;
500
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600501 ret = msm_spm_dev_init(dev, &spm_data);
Mahesh Sivasubramanian11373322012-06-14 11:17:20 -0600502
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600503 if (ret < 0)
504 pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
505
506 return ret;
507
508fail:
509 pr_err("%s: Failed reading node=%s, key=%s\n",
510 __func__, node->full_name, key);
511 return -EFAULT;
512}
513
Sathish Ambley86487e52012-06-11 13:46:11 -0700514static struct of_device_id msm_spm_match_table[] = {
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600515 {.compatible = "qcom,spm-v2"},
516 {},
517};
518
Sathish Ambley86487e52012-06-11 13:46:11 -0700519static struct platform_driver msm_spm_device_driver = {
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600520 .probe = msm_spm_dev_probe,
521 .driver = {
522 .name = "spm-v2",
523 .owner = THIS_MODULE,
524 .of_match_table = msm_spm_match_table,
525 },
526};
527
Praveen Chidambaram7347bfe2012-11-01 15:21:10 -0600528/**
529 * msm_spm_device_init(): Device tree initialization function
530 */
Praveen Chidambaramaa9d52b2012-04-02 11:09:47 -0600531int __init msm_spm_device_init(void)
532{
533 return platform_driver_register(&msm_spm_device_driver);
534}