blob: 329ac46dba78cc23aa140be0f7be5e0e0868a2f8 [file] [log] [blame]
Anirudh Ghayalccc1d5b2012-09-18 16:19:10 +05301/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
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#include <linux/module.h>
14#include <linux/err.h>
15#include <linux/kernel.h>
16#include <linux/delay.h>
17#include <linux/i2c.h>
18#include <linux/regulator/driver.h>
19#include <linux/regmap.h>
20#include <linux/regulator/onsemi-ncp6335d.h>
21
22/* registers */
23#define REG_NCP6335D_PID 0x03
24#define REG_NCP6335D_PROGVSEL1 0x10
25#define REG_NCP6335D_PROGVSEL0 0x11
26#define REG_NCP6335D_PGOOD 0x12
27#define REG_NCP6335D_TIMING 0x13
28#define REG_NCP6335D_COMMAND 0x14
29
30/* constraints */
31#define NCP6335D_MIN_VOLTAGE_UV 600000
32#define NCP6335D_STEP_VOLTAGE_UV 6250
33#define NCP6335D_MIN_SLEW_NS 166
34#define NCP6335D_MAX_SLEW_NS 1333
35
36/* bits */
37#define NCP6335D_ENABLE BIT(7)
38#define NCP6335D_DVS_PWM_MODE BIT(5)
39#define NCP6335D_PWM_MODE1 BIT(6)
40#define NCP6335D_PWM_MODE0 BIT(7)
41#define NCP6335D_PGOOD_DISCHG BIT(4)
Anirudh Ghayalc91e7e52012-12-10 11:37:36 +053042#define NCP6335D_SLEEP_MODE BIT(4)
Anirudh Ghayalccc1d5b2012-09-18 16:19:10 +053043
44#define NCP6335D_VOUT_SEL_MASK 0x7F
45#define NCP6335D_SLEW_MASK 0x18
46#define NCP6335D_SLEW_SHIFT 0x3
47
48struct ncp6335d_info {
49 struct regulator_dev *regulator;
50 struct regulator_init_data *init_data;
51 struct regmap *regmap;
52 struct device *dev;
53 unsigned int vsel_reg;
54 unsigned int mode_bit;
55 int curr_voltage;
56 int slew_rate;
57};
58
59static void dump_registers(struct ncp6335d_info *dd,
60 unsigned int reg, const char *func)
61{
62 unsigned int val = 0;
63
64 regmap_read(dd->regmap, reg, &val);
65 dev_dbg(dd->dev, "%s: NCP6335D: Reg = %x, Val = %x\n", func, reg, val);
66}
67
68static void ncp633d_slew_delay(struct ncp6335d_info *dd,
69 int prev_uV, int new_uV)
70{
71 u8 val;
72 int delay;
73
74 val = abs(prev_uV - new_uV) / NCP6335D_STEP_VOLTAGE_UV;
75 delay = (val * dd->slew_rate / 1000) + 1;
76
77 dev_dbg(dd->dev, "Slew Delay = %d\n", delay);
78
79 udelay(delay);
80}
81
82static int ncp6335d_enable(struct regulator_dev *rdev)
83{
84 int rc;
85 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
86
87 rc = regmap_update_bits(dd->regmap, dd->vsel_reg,
88 NCP6335D_ENABLE, NCP6335D_ENABLE);
89 if (rc)
90 dev_err(dd->dev, "Unable to enable regualtor rc(%d)", rc);
91
92 dump_registers(dd, dd->vsel_reg, __func__);
93
94 return rc;
95}
96
97static int ncp6335d_disable(struct regulator_dev *rdev)
98{
99 int rc;
100 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
101
102 rc = regmap_update_bits(dd->regmap, dd->vsel_reg,
103 NCP6335D_ENABLE, 0);
104 if (rc)
105 dev_err(dd->dev, "Unable to disable regualtor rc(%d)", rc);
106
107 dump_registers(dd, dd->vsel_reg, __func__);
108
109 return rc;
110}
111
112static int ncp6335d_get_voltage(struct regulator_dev *rdev)
113{
114 unsigned int val;
115 int rc;
116 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
117
118 rc = regmap_read(dd->regmap, dd->vsel_reg, &val);
119 if (rc) {
120 dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
121 return rc;
122 }
123 dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
124 NCP6335D_STEP_VOLTAGE_UV) + NCP6335D_MIN_VOLTAGE_UV;
125
126 dump_registers(dd, dd->vsel_reg, __func__);
127
128 return dd->curr_voltage;
129}
130
131static int ncp6335d_set_voltage(struct regulator_dev *rdev,
132 int min_uV, int max_uV, unsigned *selector)
133{
134 int rc, set_val, new_uV;
135 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
136
137 set_val = DIV_ROUND_UP(min_uV - NCP6335D_MIN_VOLTAGE_UV,
138 NCP6335D_STEP_VOLTAGE_UV);
139 new_uV = (set_val * NCP6335D_STEP_VOLTAGE_UV) +
140 NCP6335D_MIN_VOLTAGE_UV;
141 if (new_uV > max_uV) {
142 dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
143 min_uV, max_uV);
144 return -EINVAL;
145 }
146
147 rc = regmap_update_bits(dd->regmap, dd->vsel_reg,
148 NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
149 if (rc) {
150 dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
151 min_uV, max_uV);
152 } else {
153 ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
154 dd->curr_voltage = new_uV;
155 }
156
157 dump_registers(dd, dd->vsel_reg, __func__);
158
159 return rc;
160}
161
162static int ncp6335d_set_mode(struct regulator_dev *rdev,
163 unsigned int mode)
164{
165 int rc;
166 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
167
168 /* only FAST and NORMAL mode types are supported */
169 if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) {
170 dev_err(dd->dev, "Mode %d not supported\n", mode);
171 return -EINVAL;
172 }
173
174 rc = regmap_update_bits(dd->regmap, REG_NCP6335D_COMMAND, dd->mode_bit,
175 (mode == REGULATOR_MODE_FAST) ? dd->mode_bit : 0);
176 if (rc) {
177 dev_err(dd->dev, "Unable to set operating mode rc(%d)", rc);
178 return rc;
179 }
180
181 rc = regmap_update_bits(dd->regmap, REG_NCP6335D_COMMAND,
182 NCP6335D_DVS_PWM_MODE,
183 (mode == REGULATOR_MODE_FAST) ?
184 NCP6335D_DVS_PWM_MODE : 0);
185 if (rc)
186 dev_err(dd->dev, "Unable to set DVS trans. mode rc(%d)", rc);
187
188 dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
189
190 return rc;
191}
192
193static unsigned int ncp6335d_get_mode(struct regulator_dev *rdev)
194{
195 unsigned int val;
196 int rc;
197 struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
198
199 rc = regmap_read(dd->regmap, REG_NCP6335D_COMMAND, &val);
200 if (rc) {
201 dev_err(dd->dev, "Unable to get regulator mode rc(%d)\n", rc);
202 return rc;
203 }
204
205 dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
206
207 if (val & dd->mode_bit)
208 return REGULATOR_MODE_FAST;
209
210 return REGULATOR_MODE_NORMAL;
211}
212
213static struct regulator_ops ncp6335d_ops = {
214 .set_voltage = ncp6335d_set_voltage,
215 .get_voltage = ncp6335d_get_voltage,
216 .enable = ncp6335d_enable,
217 .disable = ncp6335d_disable,
218 .set_mode = ncp6335d_set_mode,
219 .get_mode = ncp6335d_get_mode,
220};
221
222static struct regulator_desc rdesc = {
223 .name = "ncp6335d",
224 .owner = THIS_MODULE,
225 .n_voltages = 128,
226 .ops = &ncp6335d_ops,
227};
228
229static int __devinit ncp6335d_init(struct ncp6335d_info *dd,
230 const struct ncp6335d_platform_data *pdata)
231{
232 int rc;
233 unsigned int val;
234
235 switch (pdata->default_vsel) {
236 case NCP6335D_VSEL0:
237 dd->vsel_reg = REG_NCP6335D_PROGVSEL0;
238 dd->mode_bit = NCP6335D_PWM_MODE0;
239 break;
240 case NCP6335D_VSEL1:
241 dd->vsel_reg = REG_NCP6335D_PROGVSEL1;
242 dd->mode_bit = NCP6335D_PWM_MODE1;
243 break;
244 default:
245 dev_err(dd->dev, "Invalid VSEL ID %d\n", pdata->default_vsel);
246 return -EINVAL;
247 }
248
249 /* get the current programmed voltage */
250 rc = regmap_read(dd->regmap, dd->vsel_reg, &val);
251 if (rc) {
252 dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
253 return rc;
254 }
255 dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
256 NCP6335D_STEP_VOLTAGE_UV) + NCP6335D_MIN_VOLTAGE_UV;
257
258 /* set discharge */
259 rc = regmap_update_bits(dd->regmap, REG_NCP6335D_PGOOD,
260 NCP6335D_PGOOD_DISCHG,
261 (pdata->discharge_enable ?
262 NCP6335D_PGOOD_DISCHG : 0));
263 if (rc) {
264 dev_err(dd->dev, "Unable to set Active Discharge rc(%d)\n", rc);
265 return -EINVAL;
266 }
267
268 /* set slew rate */
269 if (pdata->slew_rate_ns < NCP6335D_MIN_SLEW_NS ||
270 pdata->slew_rate_ns > NCP6335D_MAX_SLEW_NS) {
271 dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns);
272 return -EINVAL;
273 }
274 val = DIV_ROUND_UP(pdata->slew_rate_ns - NCP6335D_MIN_SLEW_NS,
275 NCP6335D_MIN_SLEW_NS);
276 val >>= 1;
277 dd->slew_rate = val * NCP6335D_MIN_SLEW_NS;
278
279 rc = regmap_update_bits(dd->regmap, REG_NCP6335D_TIMING,
280 NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT);
281 if (rc)
282 dev_err(dd->dev, "Unable to set slew rate rc(%d)\n", rc);
283
Anirudh Ghayalc91e7e52012-12-10 11:37:36 +0530284 /* Set Sleep mode bit */
285 rc = regmap_update_bits(dd->regmap, REG_NCP6335D_COMMAND,
286 NCP6335D_SLEEP_MODE, pdata->sleep_enable ?
287 NCP6335D_SLEEP_MODE : 0);
288 if (rc)
289 dev_err(dd->dev, "Unable to set sleep mode (%d)\n", rc);
290
291 dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
Anirudh Ghayalccc1d5b2012-09-18 16:19:10 +0530292 dump_registers(dd, REG_NCP6335D_PROGVSEL0, __func__);
293 dump_registers(dd, REG_NCP6335D_TIMING, __func__);
294 dump_registers(dd, REG_NCP6335D_PGOOD, __func__);
295
296 return rc;
297}
298
299static struct regmap_config ncp6335d_regmap_config = {
300 .reg_bits = 8,
301 .val_bits = 8,
302};
303
304static int __devinit ncp6335d_regulator_probe(struct i2c_client *client,
305 const struct i2c_device_id *id)
306{
307 int rc;
308 unsigned int val = 0;
309 struct ncp6335d_info *dd;
310 const struct ncp6335d_platform_data *pdata;
311
312 pdata = client->dev.platform_data;
313 if (!pdata) {
314 dev_err(&client->dev, "Platform data not specified\n");
315 return -EINVAL;
316 }
317
318 dd = devm_kzalloc(&client->dev, sizeof(*dd), GFP_KERNEL);
319 if (!dd) {
320 dev_err(&client->dev, "Unable to allocate memory\n");
321 return -ENOMEM;
322 }
323
324 dd->regmap = devm_regmap_init_i2c(client, &ncp6335d_regmap_config);
325 if (IS_ERR(dd->regmap)) {
326 dev_err(&client->dev, "Error allocating regmap\n");
327 return PTR_ERR(dd->regmap);
328 }
329
330 rc = regmap_read(dd->regmap, REG_NCP6335D_PID, &val);
331 if (rc) {
332 dev_err(&client->dev, "Unable to identify NCP6335D, rc(%d)\n",
333 rc);
334 return rc;
335 }
336 dev_info(&client->dev, "Detected Regulator NCP6335D PID = %d\n", val);
337
338 dd->init_data = pdata->init_data;
339 dd->dev = &client->dev;
340 i2c_set_clientdata(client, dd);
341
342 rc = ncp6335d_init(dd, pdata);
343 if (rc) {
344 dev_err(&client->dev, "Unable to intialize the regulator\n");
345 return -EINVAL;
346 }
347
348 dd->regulator = regulator_register(&rdesc, &client->dev,
349 dd->init_data, dd, NULL);
350 if (IS_ERR(dd->regulator)) {
351 dev_err(&client->dev, "Unable to register regulator rc(%ld)",
352 PTR_ERR(dd->regulator));
353 return PTR_ERR(dd->regulator);
354 }
355
356 return 0;
357}
358
359static int __devexit ncp6335d_regulator_remove(struct i2c_client *client)
360{
361 struct ncp6335d_info *dd = i2c_get_clientdata(client);
362
363 regulator_unregister(dd->regulator);
364
365 return 0;
366}
367
368static const struct i2c_device_id ncp6335d_id[] = {
369 {"ncp6335d", -1},
370 { },
371};
372
373static struct i2c_driver ncp6335d_regulator_driver = {
374 .driver = {
375 .name = "ncp6335d-regulator",
376 },
377 .probe = ncp6335d_regulator_probe,
378 .remove = __devexit_p(ncp6335d_regulator_remove),
379 .id_table = ncp6335d_id,
380};
Utsab Bose43a4ba62012-11-06 11:39:45 +0530381static int __init ncp6335d_regulator_init(void)
382{
383 return i2c_add_driver(&ncp6335d_regulator_driver);
384}
385subsys_initcall(ncp6335d_regulator_init);
Anirudh Ghayalccc1d5b2012-09-18 16:19:10 +0530386
Utsab Bose43a4ba62012-11-06 11:39:45 +0530387static void __exit ncp6335d_regulator_exit(void)
388{
389 i2c_del_driver(&ncp6335d_regulator_driver);
390}
391module_exit(ncp6335d_regulator_exit);
Anirudh Ghayalccc1d5b2012-09-18 16:19:10 +0530392MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver");
393MODULE_LICENSE("GPL v2");