blob: 4404f0a9a8217b4f70744e03e113c9450d82f993 [file] [log] [blame]
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +05301/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "%s: " fmt, __func__
16
17#include <linux/module.h>
18#include <linux/io.h>
19#include <linux/err.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/delay.h>
23#include <linux/errno.h>
24#include <linux/platform_device.h>
25#include <linux/regulator/driver.h>
26#include <linux/regulator/machine.h>
27
28#include <mach/msm_iomap.h>
29
30/* Address for Perf Level Registor */
31#define VDD_APC_PLEVEL_BASE (MSM_CLK_CTL_BASE + 0x0298)
32#define VDD_APC_PLEVEL(n) (VDD_APC_PLEVEL_BASE + 4 * n)
33
34/* Address for SYS_P_Level register */
35#define VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
36
37#define MV_TO_UV(mv) ((mv)*1000)
38#define UV_TO_MV(uv) (((uv)+999)/1000)
39
40#define MSM_VP_REGULATOR_DEV_NAME "vp-regulator"
41
42/**
43 * Convert Voltage to PLEVEL register value
44 * Here x is required voltage in minivolt
45 * e.g. if Required voltage is 1200mV then
46 * required value to be programmed into the
47 * Plevel register is 0x32. This equation is
48 * based on H/W logic being used in SVS controller.
49 *
50 * Here we are taking the minimum voltage step
51 * to be 12.5mV as per H/W logic and adding 0x20
52 * is for selecting the reference voltage.
53 * 750mV is minimum voltage of MSMC2 smps.
54 */
55#define VOLT_TO_BIT(x) (((x-750)/(12500/1000)) + 0x20)
Trilok Sonibb9e4132012-09-02 01:18:16 +053056#define VREG_VREF_SEL (1 << 5)
57#define VREG_VREF_SEL_SHIFT (0x5)
58#define VREG_PD_EN (1 << 6)
59#define VREG_PD_EN_SHIFT (0x6)
60#define VREG_LVL_M (0x1F)
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +053061
62/**
63 * struct msm_vp - Structure for VP
64 * @regulator_dev: structure for regulator device
65 * @current_voltage: current voltage value
66 */
67struct msm_vp {
68 struct device *dev;
69 struct regulator_dev *rdev;
70 int current_voltage;
71};
72
73/* Function to change the Vdd Level */
74static int vp_reg_set_voltage(struct regulator_dev *rdev, int min_uV,
75 int max_uV, unsigned *sel)
76{
77 struct msm_vp *vp = rdev_get_drvdata(rdev);
78 uint32_t reg_val, perf_level, plevel, cur_plevel, fine_step_volt;
79
80 reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
81 perf_level = reg_val & 0x07;
82
83 plevel = (min_uV - 750000) / 25000;
84 fine_step_volt = (min_uV - 750000) % 25000;
85
86 /**
87 * Program the new voltage level for the current perf_level
88 * in corresponding PLEVEL register.
89 */
90 cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
Trilok Soni8315b9f2012-09-02 02:48:14 +053091 /* clear lower 7 bits */
92 cur_plevel &= ~(0x7F);
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +053093 cur_plevel |= (plevel | VREG_VREF_SEL);
94 if (fine_step_volt >= 12500)
95 cur_plevel |= VREG_PD_EN;
96 writel_relaxed(cur_plevel, VDD_APC_PLEVEL(perf_level));
97
98 /* Clear the current perf level */
99 reg_val &= 0xF8;
100 writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
101
102 /* Initiate the PMIC SSBI request to change the voltage */
103 reg_val |= (BIT(7) | perf_level << 3);
104 writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
105 mb();
106 udelay(62);
107
108 if ((readl_relaxed(VDD_SVS_PLEVEL_ADDR) & 0x07) != perf_level) {
109 pr_err("Vdd Set Failed\n");
110 return -EIO;
111 }
112
113 vp->current_voltage = (min_uV / 1000);
114 return 0;
115}
116
117static int vp_reg_get_voltage(struct regulator_dev *rdev)
118{
Trilok Sonibb9e4132012-09-02 01:18:16 +0530119 uint32_t reg_val, perf_level, vlevel, cur_plevel;
120 uint32_t vref_sel, pd_en;
121 uint32_t cur_voltage;
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +0530122
Trilok Sonibb9e4132012-09-02 01:18:16 +0530123 reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
124 perf_level = reg_val & 0x07;
125
126 cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
127 vref_sel = (cur_plevel >> VREG_VREF_SEL_SHIFT) & 0x1;
128 pd_en = (cur_plevel >> VREG_PD_EN_SHIFT) & 0x1;
129 vlevel = cur_plevel & VREG_LVL_M;
130
131 cur_voltage = (750000 + (pd_en * 12500) +
132 (vlevel * 25000)) * (2 - vref_sel);
133 return cur_voltage;
Pankaj Kumar32ce1ea2012-04-04 20:29:29 +0530134}
135
136static int vp_reg_enable(struct regulator_dev *rdev)
137{
138 return 0;
139}
140
141static int vp_reg_disable(struct regulator_dev *rdev)
142{
143 return 0;
144}
145
146/* Regulator registration specific data */
147/* FIXME: should move to board-xx-regulator.c file */
148static struct regulator_consumer_supply vp_consumer =
149 REGULATOR_SUPPLY("vddx_cx", "msm-cpr");
150
151static struct regulator_init_data vp_reg_data = {
152 .constraints = {
153 .name = "vddx_c2",
154 .min_uV = 750000,
155 .max_uV = 1500000,
156 .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
157 REGULATOR_CHANGE_STATUS,
158 .valid_modes_mask = REGULATOR_MODE_NORMAL,
159 .boot_on = 1,
160 .input_uV = 0,
161 .always_on = 1,
162 },
163 .num_consumer_supplies = 1,
164 .consumer_supplies = &vp_consumer,
165};
166
167/* Regulator specific ops */
168static struct regulator_ops vp_reg_ops = {
169 .enable = vp_reg_enable,
170 .disable = vp_reg_disable,
171 .get_voltage = vp_reg_get_voltage,
172 .set_voltage = vp_reg_set_voltage,
173};
174
175/* Regulator Description */
176static struct regulator_desc vp_reg = {
177 .name = "vddcx",
178 .id = -1,
179 .ops = &vp_reg_ops,
180 .type = REGULATOR_VOLTAGE,
181};
182
183static int __devinit msm_vp_reg_probe(struct platform_device *pdev)
184{
185 struct msm_vp *vp;
186 int rc;
187
188 vp = kzalloc(sizeof(struct msm_vp), GFP_KERNEL);
189 if (!vp) {
190 pr_err("Could not allocate memory for VP\n");
191 return -ENOMEM;
192 }
193
194 vp->rdev = regulator_register(&vp_reg, NULL, &vp_reg_data, vp, NULL);
195 if (IS_ERR(vp->rdev)) {
196 rc = PTR_ERR(vp->rdev);
197 pr_err("Failed to register regulator: %d\n", rc);
198 goto error;
199 }
200
201 platform_set_drvdata(pdev, vp);
202
203 return 0;
204error:
205 kfree(vp);
206 return rc;
207}
208
209static int __devexit msm_vp_reg_remove(struct platform_device *pdev)
210{
211 struct msm_vp *vp = platform_get_drvdata(pdev);
212
213 regulator_unregister(vp->rdev);
214 platform_set_drvdata(pdev, NULL);
215 kfree(vp);
216
217 return 0;
218}
219
220static struct platform_driver msm_vp_reg_driver = {
221 .probe = msm_vp_reg_probe,
222 .remove = __devexit_p(msm_vp_reg_remove),
223 .driver = {
224 .name = MSM_VP_REGULATOR_DEV_NAME,
225 .owner = THIS_MODULE,
226 },
227};
228
229static int __init msm_vp_reg_init(void)
230{
231 return platform_driver_register(&msm_vp_reg_driver);
232}
233postcore_initcall(msm_vp_reg_init);
234
235static void __exit msm_vp_reg_exit(void)
236{
237 platform_driver_unregister(&msm_vp_reg_driver);
238}
239module_exit(msm_vp_reg_exit);
240
241MODULE_LICENSE("GPL v2");
242MODULE_DESCRIPTION("MSM VP regulator driver");
243MODULE_VERSION("1.0");
244MODULE_ALIAS("platform:" MSM_VP_REGULATOR_DEV_NAME);