Blame view

drivers/regulator/max8907-regulator.c 10.5 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
ffee19091   Gyungoh Yoo   regulator: add MA...
2
3
4
5
6
7
8
9
10
11
  /*
   * max8907-regulator.c -- support regulators in max8907
   *
   * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
   * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
   *
   * Portions based on drivers/regulator/tps65910-regulator.c,
   *     Copyright 2010 Texas Instruments Inc.
   *     Author: Graeme Gregory <gg@slimlogic.co.uk>
   *     Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
ffee19091   Gyungoh Yoo   regulator: add MA...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
   */
  
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/mfd/core.h>
  #include <linux/mfd/max8907.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
  #include <linux/regulator/of_regulator.h>
  #include <linux/regmap.h>
  #include <linux/slab.h>
  
  #define MAX8907_II2RR_VERSION_MASK	0xF0
  #define MAX8907_II2RR_VERSION_REV_A	0x00
  #define MAX8907_II2RR_VERSION_REV_B	0x10
  #define MAX8907_II2RR_VERSION_REV_C	0x30
  
  struct max8907_regulator {
  	struct regulator_desc desc[MAX8907_NUM_REGULATORS];
ffee19091   Gyungoh Yoo   regulator: add MA...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  };
  
  #define REG_MBATT() \
  	[MAX8907_MBATT] = { \
  		.name = "MBATT", \
  		.supply_name = "mbatt", \
  		.id = MAX8907_MBATT, \
  		.ops = &max8907_mbatt_ops, \
  		.type = REGULATOR_VOLTAGE, \
  		.owner = THIS_MODULE, \
  	}
  
  #define REG_LDO(ids, supply, base, min, max, step) \
  	[MAX8907_##ids] = { \
  		.name = #ids, \
  		.supply_name = supply, \
  		.id = MAX8907_##ids, \
  		.n_voltages = ((max) - (min)) / (step) + 1, \
  		.ops = &max8907_ldo_ops, \
  		.type = REGULATOR_VOLTAGE, \
  		.owner = THIS_MODULE, \
  		.min_uV = (min), \
  		.uV_step = (step), \
  		.vsel_reg = (base) + MAX8907_VOUT, \
  		.vsel_mask = 0x3f, \
  		.enable_reg = (base) + MAX8907_CTL, \
  		.enable_mask = MAX8907_MASK_LDO_EN, \
  	}
  
  #define REG_FIXED(ids, supply, voltage) \
  	[MAX8907_##ids] = { \
  		.name = #ids, \
  		.supply_name = supply, \
  		.id = MAX8907_##ids, \
  		.n_voltages = 1, \
  		.ops = &max8907_fixed_ops, \
  		.type = REGULATOR_VOLTAGE, \
  		.owner = THIS_MODULE, \
  		.min_uV = (voltage), \
  	}
  
  #define REG_OUT5V(ids, supply, base, voltage) \
  	[MAX8907_##ids] = { \
  		.name = #ids, \
  		.supply_name = supply, \
  		.id = MAX8907_##ids, \
  		.n_voltages = 1, \
  		.ops = &max8907_out5v_ops, \
  		.type = REGULATOR_VOLTAGE, \
  		.owner = THIS_MODULE, \
  		.min_uV = (voltage), \
  		.enable_reg = (base), \
  		.enable_mask = MAX8907_MASK_OUT5V_EN, \
  	}
  
  #define REG_BBAT(ids, supply, base, min, max, step) \
  	[MAX8907_##ids] = { \
  		.name = #ids, \
  		.supply_name = supply, \
  		.id = MAX8907_##ids, \
  		.n_voltages = ((max) - (min)) / (step) + 1, \
  		.ops = &max8907_bbat_ops, \
  		.type = REGULATOR_VOLTAGE, \
  		.owner = THIS_MODULE, \
  		.min_uV = (min), \
  		.uV_step = (step), \
  		.vsel_reg = (base), \
  		.vsel_mask = MAX8907_MASK_VBBATTCV, \
  	}
  
  #define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
  			750000, 3900000, 50000)
  #define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
  			650000, 2225000, 25000)
88c9d47aa   Bhumika Goyal   regulator: max890...
108
  static const struct regulator_ops max8907_mbatt_ops = {
ffee19091   Gyungoh Yoo   regulator: add MA...
109
110
111
112
113
114
115
116
117
118
  };
  
  static struct regulator_ops max8907_ldo_ops = {
  	.list_voltage = regulator_list_voltage_linear,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
  	.is_enabled = regulator_is_enabled_regmap,
  };
88c9d47aa   Bhumika Goyal   regulator: max890...
119
  static const struct regulator_ops max8907_ldo_hwctl_ops = {
ffee19091   Gyungoh Yoo   regulator: add MA...
120
121
122
123
  	.list_voltage = regulator_list_voltage_linear,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  };
88c9d47aa   Bhumika Goyal   regulator: max890...
124
  static const struct regulator_ops max8907_fixed_ops = {
ffee19091   Gyungoh Yoo   regulator: add MA...
125
126
127
128
129
130
131
132
133
  	.list_voltage = regulator_list_voltage_linear,
  };
  
  static struct regulator_ops max8907_out5v_ops = {
  	.list_voltage = regulator_list_voltage_linear,
  	.enable = regulator_enable_regmap,
  	.disable = regulator_disable_regmap,
  	.is_enabled = regulator_is_enabled_regmap,
  };
88c9d47aa   Bhumika Goyal   regulator: max890...
134
  static const struct regulator_ops max8907_out5v_hwctl_ops = {
ffee19091   Gyungoh Yoo   regulator: add MA...
135
136
  	.list_voltage = regulator_list_voltage_linear,
  };
88c9d47aa   Bhumika Goyal   regulator: max890...
137
  static const struct regulator_ops max8907_bbat_ops = {
ffee19091   Gyungoh Yoo   regulator: add MA...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  	.list_voltage = regulator_list_voltage_linear,
  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
  };
  
  static struct regulator_desc max8907_regulators[] = {
  	REG_MBATT(),
  	REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
  	REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
  	REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
  	LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
  	LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
  	LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
  	LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
  	LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
  	LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
  	LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
  	LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
  	LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
  	LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
  	LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
  	LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
  	LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
  	LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
  	LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
  	LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
  	LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
  	LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
  	LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
  	LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
  	REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
  	REG_OUT5V(OUT33V, "mbatt",  MAX8907_REG_OUT33VEN, 3300000),
  	REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
  						2400000, 3000000, 200000),
  	REG_FIXED(SDBY, "MBATT", 1200000),
  	REG_FIXED(VRTC, "MBATT", 3300000),
  };
  
  #ifdef CONFIG_OF
  
  #define MATCH(_name, _id) \
  	[MAX8907_##_id] = { \
  		.name = #_name, \
  		.driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
  	}
  
  static struct of_regulator_match max8907_matches[] = {
  	MATCH(mbatt, MBATT),
  	MATCH(sd1, SD1),
  	MATCH(sd2, SD2),
  	MATCH(sd3, SD3),
  	MATCH(ldo1, LDO1),
  	MATCH(ldo2, LDO2),
  	MATCH(ldo3, LDO3),
  	MATCH(ldo4, LDO4),
  	MATCH(ldo5, LDO5),
  	MATCH(ldo6, LDO6),
  	MATCH(ldo7, LDO7),
  	MATCH(ldo8, LDO8),
  	MATCH(ldo9, LDO9),
  	MATCH(ldo10, LDO10),
  	MATCH(ldo11, LDO11),
  	MATCH(ldo12, LDO12),
  	MATCH(ldo13, LDO13),
  	MATCH(ldo14, LDO14),
  	MATCH(ldo15, LDO15),
  	MATCH(ldo16, LDO16),
  	MATCH(ldo17, LDO17),
  	MATCH(ldo18, LDO18),
  	MATCH(ldo19, LDO19),
  	MATCH(ldo20, LDO20),
  	MATCH(out5v, OUT5V),
  	MATCH(out33v, OUT33V),
  	MATCH(bbat, BBAT),
  	MATCH(sdby, SDBY),
  	MATCH(vrtc, VRTC),
  };
  
  static int max8907_regulator_parse_dt(struct platform_device *pdev)
  {
c92f5dd2c   Axel Lin   regulator: Add mi...
218
  	struct device_node *np, *regulators;
ffee19091   Gyungoh Yoo   regulator: add MA...
219
  	int ret;
b8b27a44d   Guodong Xu   regulator: remove...
220
  	np = pdev->dev.parent->of_node;
c92f5dd2c   Axel Lin   regulator: Add mi...
221
  	if (!np)
ffee19091   Gyungoh Yoo   regulator: add MA...
222
  		return 0;
c61f14013   Sachin Kamat   regulator: max890...
223
  	regulators = of_get_child_by_name(np, "regulators");
ffee19091   Gyungoh Yoo   regulator: add MA...
224
225
226
227
228
  	if (!regulators) {
  		dev_err(&pdev->dev, "regulators node not found
  ");
  		return -EINVAL;
  	}
f40cbcb93   Axel Lin   regulator: max890...
229
  	ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
ffee19091   Gyungoh Yoo   regulator: add MA...
230
  				 ARRAY_SIZE(max8907_matches));
c92f5dd2c   Axel Lin   regulator: Add mi...
231
  	of_node_put(regulators);
ffee19091   Gyungoh Yoo   regulator: add MA...
232
233
234
235
236
237
238
239
240
  	if (ret < 0) {
  		dev_err(&pdev->dev, "Error parsing regulator init data: %d
  ",
  			ret);
  		return ret;
  	}
  
  	return 0;
  }
db5516826   Stephen Warren   regulator: max890...
241
242
243
244
245
246
247
248
249
250
  
  static inline struct regulator_init_data *match_init_data(int index)
  {
  	return max8907_matches[index].init_data;
  }
  
  static inline struct device_node *match_of_node(int index)
  {
  	return max8907_matches[index].of_node;
  }
ffee19091   Gyungoh Yoo   regulator: add MA...
251
252
253
254
255
  #else
  static int max8907_regulator_parse_dt(struct platform_device *pdev)
  {
  	return 0;
  }
db5516826   Stephen Warren   regulator: max890...
256
257
258
259
260
261
262
263
264
265
  
  static inline struct regulator_init_data *match_init_data(int index)
  {
  	return NULL;
  }
  
  static inline struct device_node *match_of_node(int index)
  {
  	return NULL;
  }
ffee19091   Gyungoh Yoo   regulator: add MA...
266
  #endif
a5023574d   Bill Pemberton   regulator: remove...
267
  static int max8907_regulator_probe(struct platform_device *pdev)
ffee19091   Gyungoh Yoo   regulator: add MA...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  {
  	struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
  	struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
  	int ret;
  	struct max8907_regulator *pmic;
  	unsigned int val;
  	int i;
  	struct regulator_config config = {};
  	struct regulator_init_data *idata;
  	const char *mbatt_rail_name = NULL;
  
  	ret = max8907_regulator_parse_dt(pdev);
  	if (ret)
  		return ret;
  
  	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
d016bdc7f   Sachin Kamat   regulator: max890...
284
  	if (!pmic)
ffee19091   Gyungoh Yoo   regulator: add MA...
285
  		return -ENOMEM;
d016bdc7f   Sachin Kamat   regulator: max890...
286

ffee19091   Gyungoh Yoo   regulator: add MA...
287
288
289
290
291
  	platform_set_drvdata(pdev, pmic);
  
  	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
  
  	/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
913b33a28   Yizhuo   regulator: max890...
292
293
294
  	ret = regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
  	if (ret)
  		return ret;
ffee19091   Gyungoh Yoo   regulator: add MA...
295
296
297
298
  	if ((val & MAX8907_II2RR_VERSION_MASK) ==
  	    MAX8907_II2RR_VERSION_REV_B) {
  		pmic->desc[MAX8907_SD1].min_uV = 637500;
  		pmic->desc[MAX8907_SD1].uV_step = 12500;
7305608bc   Axel Lin   regulator: max890...
299
300
  		pmic->desc[MAX8907_SD1].n_voltages =
  						(1425000 - 637500) / 12500 + 1;
ffee19091   Gyungoh Yoo   regulator: add MA...
301
302
303
  	}
  
  	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
f991525a1   Krzysztof Kozlowski   regulator: max890...
304
  		struct regulator_dev *rdev;
ffee19091   Gyungoh Yoo   regulator: add MA...
305
306
307
308
  		config.dev = pdev->dev.parent;
  		if (pdata)
  			idata = pdata->init_data[i];
  		else
db5516826   Stephen Warren   regulator: max890...
309
  			idata = match_init_data(i);
ffee19091   Gyungoh Yoo   regulator: add MA...
310
311
312
  		config.init_data = idata;
  		config.driver_data = pmic;
  		config.regmap = max8907->regmap_gen;
db5516826   Stephen Warren   regulator: max890...
313
  		config.of_node = match_of_node(i);
ffee19091   Gyungoh Yoo   regulator: add MA...
314
315
316
  
  		switch (pmic->desc[i].id) {
  		case MAX8907_MBATT:
5fc72f57e   Stephen Warren   regulator: max890...
317
318
319
320
  			if (idata && idata->constraints.name)
  				mbatt_rail_name = idata->constraints.name;
  			else
  				mbatt_rail_name = pmic->desc[i].name;
ffee19091   Gyungoh Yoo   regulator: add MA...
321
322
323
324
325
326
327
328
329
  			break;
  		case MAX8907_BBAT:
  		case MAX8907_SDBY:
  		case MAX8907_VRTC:
  			idata->supply_regulator = mbatt_rail_name;
  			break;
  		}
  
  		if (pmic->desc[i].ops == &max8907_ldo_ops) {
913b33a28   Yizhuo   regulator: max890...
330
  			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
ffee19091   Gyungoh Yoo   regulator: add MA...
331
  				    &val);
913b33a28   Yizhuo   regulator: max890...
332
333
  			if (ret)
  				return ret;
ffee19091   Gyungoh Yoo   regulator: add MA...
334
335
336
337
  			if ((val & MAX8907_MASK_LDO_SEQ) !=
  			    MAX8907_MASK_LDO_SEQ)
  				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
  		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
913b33a28   Yizhuo   regulator: max890...
338
  			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
ffee19091   Gyungoh Yoo   regulator: add MA...
339
  				    &val);
913b33a28   Yizhuo   regulator: max890...
340
341
  			if (ret)
  				return ret;
ffee19091   Gyungoh Yoo   regulator: add MA...
342
343
344
345
346
  			if ((val & (MAX8907_MASK_OUT5V_VINEN |
  						MAX8907_MASK_OUT5V_ENSRC)) !=
  			    MAX8907_MASK_OUT5V_ENSRC)
  				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
  		}
f991525a1   Krzysztof Kozlowski   regulator: max890...
347
  		rdev = devm_regulator_register(&pdev->dev,
5ecdf140f   Sachin Kamat   regulator: max890...
348
  						&pmic->desc[i], &config);
f991525a1   Krzysztof Kozlowski   regulator: max890...
349
  		if (IS_ERR(rdev)) {
ffee19091   Gyungoh Yoo   regulator: add MA...
350
351
352
353
  			dev_err(&pdev->dev,
  				"failed to register %s regulator
  ",
  				pmic->desc[i].name);
f991525a1   Krzysztof Kozlowski   regulator: max890...
354
  			return PTR_ERR(rdev);
ffee19091   Gyungoh Yoo   regulator: add MA...
355
356
357
358
  		}
  	}
  
  	return 0;
ffee19091   Gyungoh Yoo   regulator: add MA...
359
360
361
362
363
  }
  
  static struct platform_driver max8907_regulator_driver = {
  	.driver = {
  		   .name = "max8907-regulator",
ffee19091   Gyungoh Yoo   regulator: add MA...
364
365
  		   },
  	.probe = max8907_regulator_probe,
ffee19091   Gyungoh Yoo   regulator: add MA...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  };
  
  static int __init max8907_regulator_init(void)
  {
  	return platform_driver_register(&max8907_regulator_driver);
  }
  
  subsys_initcall(max8907_regulator_init);
  
  static void __exit max8907_reg_exit(void)
  {
  	platform_driver_unregister(&max8907_regulator_driver);
  }
  
  module_exit(max8907_reg_exit);
  
  MODULE_DESCRIPTION("MAX8907 regulator driver");
  MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
  MODULE_LICENSE("GPL v2");
d154f0a61   Axel Lin   regulator: max890...
385
  MODULE_ALIAS("platform:max8907-regulator");