1 /*
2 * Copyright (c) 2017-2018 Rockchip Electronics Co. Ltd.
3 * Author: XiaoDong Huang <derrick.huang@rock-chips.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16 #include <linux/bug.h>
17 #include <linux/debugfs.h>
18 #include <linux/delay.h>
19 #include <linux/err.h>
20 #include <linux/i2c.h>
21 #include <linux/kernel.h>
22 #include <linux/mutex.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/of_device.h>
26 #include <linux/regulator/of_regulator.h>
27 #include <linux/regulator/driver.h>
28 #include <linux/regulator/machine.h>
29 #include <linux/regulator/driver.h>
30 #include <linux/regmap.h>
31 #include <linux/types.h>
32 #include <linux/uaccess.h>
33
34 #define TPS549b22_REG_OPERATION 0x01
35 #define TPS549b22_REG_ON_OFF_CFG 0x02
36 #define TPS549b22_REG_WRITE_PROTECT 0x10
37 #define TPS549b22_REG_COMMAND 0x21
38 #define TPS549b22_REG_MRG_H 0x25
39 #define TPS549b22_REG_MRG_L 0x26
40 #define TPS549b22_REG_ST_BYTE 0x78
41 #define TPS549b22_REG_MFR_SPC_44 0xfc
42
43 #define TPS549b22_ID 0x0200
44
45 #define VOL_MSK 0x3ff
46 #define VOL_OFF_MSK 0x40
47 #define OPERATION_ON_MSK 0x80
48 #define OPERATION_MRG_MSK 0x3c
49 #define ON_OFF_CFG_OPT_MSK 0x0c
50 #define VOL_MIN_IDX 0x133
51 #define VOL_MAX_IDX 0x266
52 #define VOL_STEP_DEF 2500
53
54 #define VOL2REG(vol_sel, vol_step) \
55 ((vol_sel) / (vol_step) & VOL_MSK)
56 #define REG2VOL(val, vol_step) \
57 ((vol_step) * ((val) & VOL_MSK))
58
59 #define TPS549b22_NUM_REGULATORS 1
60
61 struct tps549b22 {
62 struct device *dev;
63 struct i2c_client *i2c;
64 int num_regulators;
65 struct regulator_dev **rdev;
66 struct regmap *regmap_8bits;
67 struct regmap *regmap_16bits;
68 int vol_step;
69 };
70
71 struct tps549b22_board {
72 struct regulator_init_data
73 *tps549b22_init_data[TPS549b22_NUM_REGULATORS];
74 struct device_node *of_node[TPS549b22_NUM_REGULATORS];
75 };
76
77 struct tps549b22_regulator_subdev {
78 int id;
79 struct regulator_init_data *initdata;
80 struct device_node *reg_node;
81 };
82
tps549b22_dcdc_list_voltage(struct regulator_dev * rdev,unsigned int index)83 static int tps549b22_dcdc_list_voltage(struct regulator_dev *rdev,
84 unsigned int index)
85 {
86 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
87
88 if (index + VOL_MIN_IDX > VOL_MAX_IDX)
89 return -EINVAL;
90
91 return REG2VOL(index + VOL_MIN_IDX, tps549b22->vol_step);
92 }
93
tps549b22_reg_init(struct tps549b22 * tps549b22)94 static int tps549b22_reg_init(struct tps549b22 *tps549b22)
95 {
96 if (regmap_update_bits(tps549b22->regmap_8bits,
97 TPS549b22_REG_OPERATION,
98 OPERATION_ON_MSK,
99 0x80) == 0)
100 return regmap_update_bits(tps549b22->regmap_8bits,
101 TPS549b22_REG_ON_OFF_CFG,
102 ON_OFF_CFG_OPT_MSK,
103 0x0c);
104
105 dev_err(tps549b22->dev, "regulator init err\n");
106
107 return -1;
108 }
109
tps549b22dcdc_is_enabled(struct regulator_dev * rdev)110 static int tps549b22dcdc_is_enabled(struct regulator_dev *rdev)
111 {
112 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
113 int err;
114 u32 val;
115
116 err = regmap_read(tps549b22->regmap_8bits, TPS549b22_REG_ST_BYTE, &val);
117 if (err)
118 return 0;
119
120 return !(val & VOL_OFF_MSK);
121 }
122
tps549b22dcdc_enable(struct regulator_dev * rdev)123 static int tps549b22dcdc_enable(struct regulator_dev *rdev)
124 {
125 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
126
127 return regmap_update_bits(tps549b22->regmap_8bits,
128 TPS549b22_REG_OPERATION,
129 OPERATION_ON_MSK,
130 0x80);
131 }
132
tps549b22dcdc_disable(struct regulator_dev * rdev)133 static int tps549b22dcdc_disable(struct regulator_dev *rdev)
134 {
135 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
136
137 return regmap_update_bits(tps549b22->regmap_8bits,
138 TPS549b22_REG_OPERATION,
139 OPERATION_ON_MSK,
140 0);
141 }
142
tps549b22dcdc_get_voltage(struct regulator_dev * rdev)143 static int tps549b22dcdc_get_voltage(struct regulator_dev *rdev)
144 {
145 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
146 int err;
147 u32 val = 0;
148
149 err = regmap_read(tps549b22->regmap_16bits,
150 TPS549b22_REG_COMMAND,
151 &val);
152 if (!err)
153 return REG2VOL(val, tps549b22->vol_step);
154
155 return -1;
156 }
157
tps549b22dcdc_set_voltage(struct regulator_dev * rdev,int min_uV,int max_uV,unsigned int * selector)158 static int tps549b22dcdc_set_voltage(struct regulator_dev *rdev,
159 int min_uV,
160 int max_uV,
161 unsigned int *selector)
162 {
163 struct tps549b22 *tps549b22 = rdev_get_drvdata(rdev);
164 int val;
165 int err;
166
167 if (min_uV < REG2VOL(VOL_MIN_IDX, tps549b22->vol_step) ||
168 min_uV > REG2VOL(VOL_MAX_IDX, tps549b22->vol_step)) {
169 dev_warn(rdev_get_dev(rdev),
170 "this voltage is out of limit! voltage set is %d mv\n",
171 REG2VOL(min_uV, tps549b22->vol_step));
172 return -EINVAL;
173 }
174
175 for (val = VOL_MIN_IDX; val <= VOL_MAX_IDX; val++)
176 if (REG2VOL(val, tps549b22->vol_step) >= min_uV)
177 break;
178
179 if (REG2VOL(val, tps549b22->vol_step) > max_uV)
180 dev_warn(rdev_get_dev(rdev),
181 "this voltage is not support! voltage set is %d mv\n",
182 REG2VOL(val, tps549b22->vol_step));
183
184 err = regmap_update_bits(tps549b22->regmap_16bits,
185 TPS549b22_REG_COMMAND,
186 VOL_MSK,
187 val);
188 if (err)
189 dev_err(rdev_get_dev(rdev),
190 "set voltage is error! voltage set is %d mv\n",
191 REG2VOL(val, tps549b22->vol_step));
192
193 return err;
194 }
195
196 static struct regulator_ops tps549b22dcdc_ops = {
197 .set_voltage = tps549b22dcdc_set_voltage,
198 .get_voltage = tps549b22dcdc_get_voltage,
199 .is_enabled = tps549b22dcdc_is_enabled,
200 .enable = tps549b22dcdc_enable,
201 .disable = tps549b22dcdc_disable,
202 .list_voltage = tps549b22_dcdc_list_voltage,
203 };
204
205 static struct regulator_desc regulators[] = {
206 {
207 .name = "tps549b22_DCDC1",
208 .id = 0,
209 .ops = &tps549b22dcdc_ops,
210 .n_voltages = VOL_MAX_IDX - VOL_MIN_IDX + 1,
211 .type = REGULATOR_VOLTAGE,
212 .owner = THIS_MODULE,
213 },
214 };
215
216 static struct of_regulator_match tps549b22_reg_matches[] = {
217 { .name = "tps549b22_dcdc1", .driver_data = (void *)0},
218 };
219
220 static struct tps549b22_board *
tps549b22_parse_dt(struct tps549b22 * tps549b22)221 tps549b22_parse_dt(struct tps549b22 *tps549b22)
222 {
223 struct tps549b22_board *pdata;
224 struct device_node *regs;
225 struct device_node *tps549b22_np;
226 int count;
227
228 tps549b22_np = of_node_get(tps549b22->dev->of_node);
229 if (!tps549b22_np) {
230 pr_err("could not find pmic sub-node\n");
231 goto err;
232 }
233
234 regs = of_get_child_by_name(tps549b22_np, "regulators");
235 if (!regs)
236 goto err;
237
238 count = of_regulator_match(tps549b22->dev,
239 regs,
240 tps549b22_reg_matches,
241 TPS549b22_NUM_REGULATORS);
242
243 if (of_property_read_u32(tps549b22_reg_matches[0].of_node,
244 "voltage-step",
245 &tps549b22->vol_step))
246 tps549b22->vol_step = VOL_STEP_DEF;
247
248 dev_info(tps549b22->dev, "voltage-step: %duV\n", tps549b22->vol_step);
249
250 of_node_put(regs);
251 of_node_put(tps549b22_np);
252
253 if (count <= 0)
254 goto err;
255
256 pdata = devm_kzalloc(tps549b22->dev, sizeof(*pdata), GFP_KERNEL);
257 if (!pdata)
258 goto err;
259
260 pdata->tps549b22_init_data[0] = tps549b22_reg_matches[0].init_data;
261 pdata->of_node[0] = tps549b22_reg_matches[0].of_node;
262
263 return pdata;
264
265 err:
266 return NULL;
267 }
268
269 static const struct of_device_id tps549b22_of_match[] = {
270 {.compatible = "ti,tps549b22"},
271 { },
272 };
273 MODULE_DEVICE_TABLE(of, tps549b22_of_match);
274
275 static const struct regmap_config tps549b22_8bits_regmap_config = {
276 .reg_bits = 8,
277 .val_bits = 8,
278 .max_register = TPS549b22_REG_MFR_SPC_44 + 1,
279 .cache_type = REGCACHE_NONE,
280 };
281
282 static const struct regmap_config tps549b22_16bits_regmap_config = {
283 .reg_bits = 8,
284 .val_bits = 16,
285 .max_register = TPS549b22_REG_MFR_SPC_44 + 1,
286 .cache_type = REGCACHE_NONE,
287 .val_format_endian = REGMAP_ENDIAN_LITTLE,
288 };
289
tps549b22_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)290 static int tps549b22_i2c_probe(struct i2c_client *i2c,
291 const struct i2c_device_id *id)
292 {
293 struct tps549b22 *tps549b22;
294 struct tps549b22_board *pdev = NULL;
295 const struct of_device_id *match;
296 struct regulator_config config = { };
297 struct regulator_dev *rdev;
298 struct regulator_init_data *reg_data;
299 int ret;
300 u32 val;
301
302 if (i2c->dev.of_node) {
303 match = of_match_device(tps549b22_of_match, &i2c->dev);
304 if (!match) {
305 pr_err("Failed to find matching dt id\n");
306 return -EINVAL;
307 }
308 }
309
310 tps549b22 = devm_kzalloc(&i2c->dev,
311 sizeof(struct tps549b22),
312 GFP_KERNEL);
313 if (!tps549b22) {
314 ret = -ENOMEM;
315 goto err;
316 }
317
318 tps549b22->regmap_8bits =
319 devm_regmap_init_i2c(i2c, &tps549b22_8bits_regmap_config);
320 if (IS_ERR(tps549b22->regmap_8bits)) {
321 dev_err(&i2c->dev, "8 bits regmap initialization failed\n");
322 return PTR_ERR(tps549b22->regmap_8bits);
323 }
324
325 tps549b22->regmap_16bits =
326 devm_regmap_init_i2c(i2c, &tps549b22_16bits_regmap_config);
327 if (IS_ERR(tps549b22->regmap_16bits)) {
328 dev_err(&i2c->dev, "16 bits regmap initialization failed\n");
329 return PTR_ERR(tps549b22->regmap_16bits);
330 }
331
332 tps549b22->i2c = i2c;
333 tps549b22->dev = &i2c->dev;
334 i2c_set_clientdata(i2c, tps549b22);
335
336 ret = regmap_read(tps549b22->regmap_16bits,
337 TPS549b22_REG_MFR_SPC_44,
338 &val);
339 if (!ret) {
340 if (val != TPS549b22_ID)
341 dev_warn(tps549b22->dev,
342 "The device is not tps549b22 0x%x\n",
343 val);
344 } else {
345 dev_err(tps549b22->dev,
346 "Tps549b22_reg_read err, ret = %d\n",
347 ret);
348 return -EINVAL;
349 }
350
351 tps549b22_reg_init(tps549b22);
352
353 if (tps549b22->dev->of_node)
354 pdev = tps549b22_parse_dt(tps549b22);
355
356 if (pdev) {
357 tps549b22->num_regulators = TPS549b22_NUM_REGULATORS;
358 tps549b22->rdev =
359 devm_kmalloc_array(tps549b22->dev,
360 TPS549b22_NUM_REGULATORS,
361 sizeof(struct regulator_dev *),
362 GFP_KERNEL);
363 if (!tps549b22->rdev)
364 return -ENOMEM;
365
366 /* Instantiate the regulators */
367 reg_data = pdev->tps549b22_init_data[0];
368 config.dev = tps549b22->dev;
369 config.driver_data = tps549b22;
370 if (tps549b22->dev->of_node)
371 config.of_node = pdev->of_node[0];
372
373 config.init_data = reg_data;
374
375 rdev = devm_regulator_register(tps549b22->dev,
376 ®ulators[0],
377 &config);
378 if (IS_ERR(rdev)) {
379 pr_err("failed to register regulator\n");
380 goto err;
381 }
382
383 tps549b22->rdev[0] = rdev;
384 }
385
386 return 0;
387 err:
388 return ret;
389 }
390
tps549b22_i2c_remove(struct i2c_client * i2c)391 static int tps549b22_i2c_remove(struct i2c_client *i2c)
392 {
393 i2c_set_clientdata(i2c, NULL);
394
395 return 0;
396 }
397
398 static const struct i2c_device_id tps549b22_i2c_id[] = {
399 {"tps549b22", 0},
400 { }
401 };
402
403 MODULE_DEVICE_TABLE(i2c, tps549b22_i2c_id);
404
405 static struct i2c_driver tps549b22_i2c_driver = {
406 .driver = {
407 .name = "tps549b22",
408 .of_match_table = of_match_ptr(tps549b22_of_match),
409 },
410 .probe = tps549b22_i2c_probe,
411 .remove = tps549b22_i2c_remove,
412 .id_table = tps549b22_i2c_id,
413 };
414
tps549b22_module_init(void)415 static int __init tps549b22_module_init(void)
416 {
417 int ret;
418
419 ret = i2c_add_driver(&tps549b22_i2c_driver);
420
421 if (ret != 0)
422 pr_err("Failed to register I2C driver: %d\n", ret);
423
424 return ret;
425 }
426 subsys_initcall_sync(tps549b22_module_init);
427
tps549b22_module_exit(void)428 static void __exit tps549b22_module_exit(void)
429 {
430 i2c_del_driver(&tps549b22_i2c_driver);
431 }
432 module_exit(tps549b22_module_exit);
433
434 MODULE_LICENSE("GPL");
435
436 MODULE_AUTHOR("derrick.huang@rock-chips.com");
437 MODULE_DESCRIPTION(" tps549b22 dcdc driver");
438