Blame view

drivers/regulator/lm363x-regulator.c 10.3 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
3a8d1a73a   Milo Kim   regulator: add LM...
2
3
4
5
6
7
  /*
   * TI LM363X Regulator Driver
   *
   * Copyright 2015 Texas Instruments
   *
   * Author: Milo Kim <milo.kim@ti.com>
3a8d1a73a   Milo Kim   regulator: add LM...
8
9
10
11
12
13
14
15
   */
  
  #include <linux/err.h>
  #include <linux/kernel.h>
  #include <linux/mfd/ti-lmu.h>
  #include <linux/mfd/ti-lmu-register.h>
  #include <linux/module.h>
  #include <linux/of.h>
b2d751b7f   Linus Walleij   regulator: lm363x...
16
  #include <linux/gpio/consumer.h>
3a8d1a73a   Milo Kim   regulator: add LM...
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/of_regulator.h>
  #include <linux/slab.h>
  
  /* LM3631 */
  #define LM3631_BOOST_VSEL_MAX		0x25
  #define LM3631_LDO_VSEL_MAX		0x28
  #define LM3631_CONT_VSEL_MAX		0x03
  #define LM3631_VBOOST_MIN		4500000
  #define LM3631_VCONT_MIN		1800000
  #define LM3631_VLDO_MIN			4000000
  #define ENABLE_TIME_USEC		1000
  
  /* LM3632 */
  #define LM3632_BOOST_VSEL_MAX		0x26
1e2cc8c5e   Axel Lin   regulator: lm363x...
33
  #define LM3632_LDO_VSEL_MAX		0x28
3a8d1a73a   Milo Kim   regulator: add LM...
34
35
  #define LM3632_VBOOST_MIN		4500000
  #define LM3632_VLDO_MIN			4000000
bff5e8071   Dan Murphy   regulator: lm363x...
36
37
  /* LM36274 */
  #define LM36274_BOOST_VSEL_MAX		0x3f
962f170d9   Axel Lin   regulator: lm363x...
38
  #define LM36274_LDO_VSEL_MAX		0x32
bff5e8071   Dan Murphy   regulator: lm363x...
39
  #define LM36274_VOLTAGE_MIN		4000000
3a8d1a73a   Milo Kim   regulator: add LM...
40
41
42
  /* Common */
  #define LM363X_STEP_50mV		50000
  #define LM363X_STEP_500mV		500000
faa5cf3af   Axel Lin   regulator: lm363x...
43
  static const int ldo_cont_enable_time[] = {
3a8d1a73a   Milo Kim   regulator: add LM...
44
45
46
47
48
  	0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
  };
  
  static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
  {
3a8d1a73a   Milo Kim   regulator: add LM...
49
  	enum lm363x_regulator_id id = rdev_get_id(rdev);
8a76f1072   Axel Lin   regulator: lm363x...
50
  	unsigned int val, addr, mask;
3a8d1a73a   Milo Kim   regulator: add LM...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  
  	switch (id) {
  	case LM3631_LDO_CONT:
  		addr = LM3631_REG_ENTIME_VCONT;
  		mask = LM3631_ENTIME_CONT_MASK;
  		break;
  	case LM3631_LDO_OREF:
  		addr = LM3631_REG_ENTIME_VOREF;
  		mask = LM3631_ENTIME_MASK;
  		break;
  	case LM3631_LDO_POS:
  		addr = LM3631_REG_ENTIME_VPOS;
  		mask = LM3631_ENTIME_MASK;
  		break;
  	case LM3631_LDO_NEG:
  		addr = LM3631_REG_ENTIME_VNEG;
  		mask = LM3631_ENTIME_MASK;
  		break;
  	default:
  		return 0;
  	}
8a76f1072   Axel Lin   regulator: lm363x...
72
  	if (regmap_read(rdev->regmap, addr, &val))
3a8d1a73a   Milo Kim   regulator: add LM...
73
74
75
76
77
78
79
80
81
  		return -EINVAL;
  
  	val = (val & mask) >> LM3631_ENTIME_SHIFT;
  
  	if (id == LM3631_LDO_CONT)
  		return ldo_cont_enable_time[val];
  	else
  		return ENABLE_TIME_USEC * val;
  }
55c083d89   Axel Lin   regulator: lm363x...
82
  static const struct regulator_ops lm363x_boost_voltage_table_ops = {
3a8d1a73a   Milo Kim   regulator: add LM...
83
84
85
86
  	.list_voltage     = regulator_list_voltage_linear,
  	.set_voltage_sel  = regulator_set_voltage_sel_regmap,
  	.get_voltage_sel  = regulator_get_voltage_sel_regmap,
  };
55c083d89   Axel Lin   regulator: lm363x...
87
  static const struct regulator_ops lm363x_regulator_voltage_table_ops = {
3a8d1a73a   Milo Kim   regulator: add LM...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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
  	.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,
  	.enable_time      = lm363x_regulator_enable_time,
  };
  
  static const struct regulator_desc lm363x_regulator_desc[] = {
  	/* LM3631 */
  	{
  		.name           = "vboost",
  		.of_match	= "vboost",
  		.id             = LM3631_BOOST,
  		.ops            = &lm363x_boost_voltage_table_ops,
  		.n_voltages     = LM3631_BOOST_VSEL_MAX + 1,
  		.min_uV         = LM3631_VBOOST_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3631_REG_VOUT_BOOST,
  		.vsel_mask      = LM3631_VOUT_MASK,
  	},
  	{
  		.name           = "ldo_cont",
  		.of_match	= "vcont",
  		.id             = LM3631_LDO_CONT,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3631_CONT_VSEL_MAX + 1,
  		.min_uV         = LM3631_VCONT_MIN,
  		.uV_step        = LM363X_STEP_500mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3631_REG_VOUT_CONT,
  		.vsel_mask      = LM3631_VOUT_CONT_MASK,
  		.enable_reg     = LM3631_REG_LDO_CTRL2,
  		.enable_mask    = LM3631_EN_CONT_MASK,
  	},
  	{
  		.name           = "ldo_oref",
  		.of_match	= "voref",
  		.id             = LM3631_LDO_OREF,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
  		.min_uV         = LM3631_VLDO_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3631_REG_VOUT_OREF,
  		.vsel_mask      = LM3631_VOUT_MASK,
  		.enable_reg     = LM3631_REG_LDO_CTRL1,
  		.enable_mask    = LM3631_EN_OREF_MASK,
  	},
  	{
  		.name           = "ldo_vpos",
  		.of_match	= "vpos",
  		.id             = LM3631_LDO_POS,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
  		.min_uV         = LM3631_VLDO_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3631_REG_VOUT_POS,
  		.vsel_mask      = LM3631_VOUT_MASK,
  		.enable_reg     = LM3631_REG_LDO_CTRL1,
  		.enable_mask    = LM3631_EN_VPOS_MASK,
  	},
  	{
  		.name           = "ldo_vneg",
  		.of_match	= "vneg",
  		.id             = LM3631_LDO_NEG,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
  		.min_uV         = LM3631_VLDO_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3631_REG_VOUT_NEG,
  		.vsel_mask      = LM3631_VOUT_MASK,
  		.enable_reg     = LM3631_REG_LDO_CTRL1,
  		.enable_mask    = LM3631_EN_VNEG_MASK,
  	},
  	/* LM3632 */
  	{
  		.name           = "vboost",
  		.of_match	= "vboost",
  		.id             = LM3632_BOOST,
  		.ops            = &lm363x_boost_voltage_table_ops,
  		.n_voltages     = LM3632_BOOST_VSEL_MAX + 1,
  		.min_uV         = LM3632_VBOOST_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3632_REG_VOUT_BOOST,
  		.vsel_mask      = LM3632_VOUT_MASK,
  	},
  	{
  		.name           = "ldo_vpos",
  		.of_match	= "vpos",
  		.id             = LM3632_LDO_POS,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
  		.min_uV         = LM3632_VLDO_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3632_REG_VOUT_POS,
  		.vsel_mask      = LM3632_VOUT_MASK,
  		.enable_reg     = LM3632_REG_BIAS_CONFIG,
  		.enable_mask    = LM3632_EN_VPOS_MASK,
  	},
  	{
  		.name           = "ldo_vneg",
  		.of_match	= "vneg",
  		.id             = LM3632_LDO_NEG,
  		.ops            = &lm363x_regulator_voltage_table_ops,
  		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
  		.min_uV         = LM3632_VLDO_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM3632_REG_VOUT_NEG,
  		.vsel_mask      = LM3632_VOUT_MASK,
  		.enable_reg     = LM3632_REG_BIAS_CONFIG,
  		.enable_mask    = LM3632_EN_VNEG_MASK,
  	},
bff5e8071   Dan Murphy   regulator: lm363x...
216
217
218
219
220
221
222
  
  	/* LM36274 */
  	{
  		.name           = "vboost",
  		.of_match	= "vboost",
  		.id             = LM36274_BOOST,
  		.ops            = &lm363x_boost_voltage_table_ops,
962f170d9   Axel Lin   regulator: lm363x...
223
  		.n_voltages     = LM36274_BOOST_VSEL_MAX + 1,
bff5e8071   Dan Murphy   regulator: lm363x...
224
225
226
227
228
229
230
231
232
233
234
235
  		.min_uV         = LM36274_VOLTAGE_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM36274_REG_VOUT_BOOST,
  		.vsel_mask      = LM36274_VOUT_MASK,
  	},
  	{
  		.name           = "ldo_vpos",
  		.of_match	= "vpos",
  		.id             = LM36274_LDO_POS,
  		.ops            = &lm363x_regulator_voltage_table_ops,
962f170d9   Axel Lin   regulator: lm363x...
236
  		.n_voltages     = LM36274_LDO_VSEL_MAX + 1,
bff5e8071   Dan Murphy   regulator: lm363x...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  		.min_uV         = LM36274_VOLTAGE_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM36274_REG_VOUT_POS,
  		.vsel_mask      = LM36274_VOUT_MASK,
  		.enable_reg     = LM36274_REG_BIAS_CONFIG_1,
  		.enable_mask    = LM36274_EN_VPOS_MASK,
  	},
  	{
  		.name           = "ldo_vneg",
  		.of_match	= "vneg",
  		.id             = LM36274_LDO_NEG,
  		.ops            = &lm363x_regulator_voltage_table_ops,
962f170d9   Axel Lin   regulator: lm363x...
251
  		.n_voltages     = LM36274_LDO_VSEL_MAX + 1,
bff5e8071   Dan Murphy   regulator: lm363x...
252
253
254
255
256
257
258
259
260
  		.min_uV         = LM36274_VOLTAGE_MIN,
  		.uV_step        = LM363X_STEP_50mV,
  		.type           = REGULATOR_VOLTAGE,
  		.owner          = THIS_MODULE,
  		.vsel_reg       = LM36274_REG_VOUT_NEG,
  		.vsel_mask      = LM36274_VOUT_MASK,
  		.enable_reg     = LM36274_REG_BIAS_CONFIG_1,
  		.enable_mask    = LM36274_EN_VNEG_MASK,
  	},
3a8d1a73a   Milo Kim   regulator: add LM...
261
  };
b2d751b7f   Linus Walleij   regulator: lm363x...
262
  static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)
3a8d1a73a   Milo Kim   regulator: add LM...
263
264
265
266
  {
  	/*
  	 * Check LCM_EN1/2_GPIO is configured.
  	 * Those pins are used for enabling VPOS/VNEG LDOs.
e8a33aa0e   Linus Walleij   regulator: lm363x...
267
268
  	 * Do not use devm* here: the regulator core takes over the
  	 * lifecycle management of the GPIO descriptor.
3a8d1a73a   Milo Kim   regulator: add LM...
269
270
271
  	 */
  	switch (id) {
  	case LM3632_LDO_POS:
bff5e8071   Dan Murphy   regulator: lm363x...
272
  	case LM36274_LDO_POS:
e8a33aa0e   Linus Walleij   regulator: lm363x...
273
  		return gpiod_get_index_optional(dev, "enable", 0,
63239e4bf   Linus Walleij   regulator: Fetch ...
274
  				GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
3a8d1a73a   Milo Kim   regulator: add LM...
275
  	case LM3632_LDO_NEG:
bff5e8071   Dan Murphy   regulator: lm363x...
276
  	case LM36274_LDO_NEG:
e8a33aa0e   Linus Walleij   regulator: lm363x...
277
  		return gpiod_get_index_optional(dev, "enable", 1,
63239e4bf   Linus Walleij   regulator: Fetch ...
278
  				GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
3a8d1a73a   Milo Kim   regulator: add LM...
279
  	default:
b2d751b7f   Linus Walleij   regulator: lm363x...
280
  		return NULL;
3a8d1a73a   Milo Kim   regulator: add LM...
281
282
  	}
  }
bff5e8071   Dan Murphy   regulator: lm363x...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id)
  {
  	int ext_en_mask = 0;
  
  	switch (id) {
  	case LM3632_LDO_POS:
  	case LM3632_LDO_NEG:
  		ext_en_mask = LM3632_EXT_EN_MASK;
  		break;
  	case LM36274_LDO_POS:
  	case LM36274_LDO_NEG:
  		ext_en_mask = LM36274_EXT_EN_MASK;
  		break;
  	default:
  		return -ENODEV;
  	}
  
  	return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg,
  				 ext_en_mask, ext_en_mask);
  }
3a8d1a73a   Milo Kim   regulator: add LM...
303
304
305
  static int lm363x_regulator_probe(struct platform_device *pdev)
  {
  	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
3a8d1a73a   Milo Kim   regulator: add LM...
306
307
308
309
310
  	struct regmap *regmap = lmu->regmap;
  	struct regulator_config cfg = { };
  	struct regulator_dev *rdev;
  	struct device *dev = &pdev->dev;
  	int id = pdev->id;
b2d751b7f   Linus Walleij   regulator: lm363x...
311
312
  	struct gpio_desc *gpiod;
  	int ret;
3a8d1a73a   Milo Kim   regulator: add LM...
313

3a8d1a73a   Milo Kim   regulator: add LM...
314
  	cfg.dev = dev;
3a8d1a73a   Milo Kim   regulator: add LM...
315
316
317
318
319
320
  	cfg.regmap = regmap;
  
  	/*
  	 * LM3632 LDOs can be controlled by external pin.
  	 * Register update is required if the pin is used.
  	 */
b2d751b7f   Linus Walleij   regulator: lm363x...
321
  	gpiod = lm363x_regulator_of_get_enable_gpio(dev, id);
c68f47aa0   Axel Lin   regulator: lm363x...
322
323
  	if (IS_ERR(gpiod))
  		return PTR_ERR(gpiod);
b2d751b7f   Linus Walleij   regulator: lm363x...
324
325
  	if (gpiod) {
  		cfg.ena_gpiod = gpiod;
bff5e8071   Dan Murphy   regulator: lm363x...
326
  		ret = lm363x_regulator_set_ext_en(regmap, id);
3a8d1a73a   Milo Kim   regulator: add LM...
327
  		if (ret) {
c68f47aa0   Axel Lin   regulator: lm363x...
328
  			gpiod_put(gpiod);
3a8d1a73a   Milo Kim   regulator: add LM...
329
330
331
332
333
334
335
336
337
338
339
340
341
  			dev_err(dev, "External pin err: %d
  ", ret);
  			return ret;
  		}
  	}
  
  	rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg);
  	if (IS_ERR(rdev)) {
  		ret = PTR_ERR(rdev);
  		dev_err(dev, "[%d] regulator register err: %d
  ", id, ret);
  		return ret;
  	}
3a8d1a73a   Milo Kim   regulator: add LM...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  	return 0;
  }
  
  static struct platform_driver lm363x_regulator_driver = {
  	.probe = lm363x_regulator_probe,
  	.driver = {
  		.name = "lm363x-regulator",
  	},
  };
  
  module_platform_driver(lm363x_regulator_driver);
  
  MODULE_DESCRIPTION("TI LM363X Regulator Driver");
  MODULE_AUTHOR("Milo Kim");
  MODULE_LICENSE("GPL v2");
  MODULE_ALIAS("platform:lm363x-regulator");