Blame view

drivers/regulator/max8952.c 8.8 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
2
3
4
5
6
  /*
   * max8952.c - Voltage and current regulation for the Maxim 8952
   *
   * Copyright (C) 2010 Samsung Electronics
   * MyungJoo Ham <myungjoo.ham@samsung.com>
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
7
8
9
10
11
12
13
14
15
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/i2c.h>
  #include <linux/err.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/max8952.h>
d7a261c2d   Linus Walleij   regulator: max895...
16
  #include <linux/gpio/consumer.h>
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
17
  #include <linux/io.h>
3ff4aa95b   Tomasz Figa   regulator: max895...
18
  #include <linux/of.h>
3ff4aa95b   Tomasz Figa   regulator: max895...
19
  #include <linux/regulator/of_regulator.h>
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  #include <linux/slab.h>
  
  /* Registers */
  enum {
  	MAX8952_REG_MODE0,
  	MAX8952_REG_MODE1,
  	MAX8952_REG_MODE2,
  	MAX8952_REG_MODE3,
  	MAX8952_REG_CONTROL,
  	MAX8952_REG_SYNC,
  	MAX8952_REG_RAMP,
  	MAX8952_REG_CHIP_ID1,
  	MAX8952_REG_CHIP_ID2,
  };
  
  struct max8952_data {
  	struct i2c_client	*client;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
37
  	struct max8952_platform_data *pdata;
fd742eaab   Linus Walleij   regulator: max895...
38
39
  	struct gpio_desc *vid0_gpiod;
  	struct gpio_desc *vid1_gpiod;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
40
41
  	bool vid0;
  	bool vid1;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
42
43
44
45
46
  };
  
  static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
  {
  	int ret = i2c_smbus_read_byte_data(max8952->client, reg);
a5f8f9630   Sachin Kamat   regulator: max895...
47

202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
48
49
50
51
52
53
54
55
56
57
58
  	if (ret > 0)
  		ret &= 0xff;
  
  	return ret;
  }
  
  static int max8952_write_reg(struct max8952_data *max8952,
  		u8 reg, u8 value)
  {
  	return i2c_smbus_write_byte_data(max8952->client, reg, value);
  }
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
59
60
61
62
63
64
65
  static int max8952_list_voltage(struct regulator_dev *rdev,
  		unsigned int selector)
  {
  	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
  
  	if (rdev_get_id(rdev) != 0)
  		return -EINVAL;
b9b49af5e   Axel Lin   regulator: max895...
66
  	return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
67
  }
b9b49af5e   Axel Lin   regulator: max895...
68
  static int max8952_get_voltage_sel(struct regulator_dev *rdev)
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
69
70
71
72
73
74
75
76
  {
  	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
  	u8 vid = 0;
  
  	if (max8952->vid0)
  		vid += 1;
  	if (max8952->vid1)
  		vid += 2;
b9b49af5e   Axel Lin   regulator: max895...
77
  	return vid;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
78
  }
6ea67d04b   Axel Lin   regulator: Conver...
79
80
  static int max8952_set_voltage_sel(struct regulator_dev *rdev,
  				   unsigned selector)
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
81
82
  {
  	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
83

fd742eaab   Linus Walleij   regulator: max895...
84
  	if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
85
86
87
  		/* DVS not supported */
  		return -EPERM;
  	}
6ea67d04b   Axel Lin   regulator: Conver...
88
89
  	max8952->vid0 = selector & 0x1;
  	max8952->vid1 = (selector >> 1) & 0x1;
fd742eaab   Linus Walleij   regulator: max895...
90
91
  	gpiod_set_value(max8952->vid0_gpiod, max8952->vid0);
  	gpiod_set_value(max8952->vid1_gpiod, max8952->vid1);
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
92
93
94
  
  	return 0;
  }
6e09f4af1   Bhumika Goyal   regulator: max895...
95
  static const struct regulator_ops max8952_ops = {
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
96
  	.list_voltage		= max8952_list_voltage,
b9b49af5e   Axel Lin   regulator: max895...
97
  	.get_voltage_sel	= max8952_get_voltage_sel,
6ea67d04b   Axel Lin   regulator: Conver...
98
  	.set_voltage_sel	= max8952_set_voltage_sel,
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
99
  };
bd6ff0d6a   Axel Lin   regulator: max895...
100
  static const struct regulator_desc regulator = {
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
101
102
103
104
105
106
107
  	.name		= "MAX8952_VOUT",
  	.id		= 0,
  	.n_voltages	= MAX8952_NUM_DVS_MODE,
  	.ops		= &max8952_ops,
  	.type		= REGULATOR_VOLTAGE,
  	.owner		= THIS_MODULE,
  };
3ff4aa95b   Tomasz Figa   regulator: max895...
108
  #ifdef CONFIG_OF
cfe6e3334   Jingoo Han   regulator: max895...
109
  static const struct of_device_id max8952_dt_match[] = {
3ff4aa95b   Tomasz Figa   regulator: max895...
110
111
112
113
114
115
116
117
118
119
120
121
122
  	{ .compatible = "maxim,max8952" },
  	{},
  };
  MODULE_DEVICE_TABLE(of, max8952_dt_match);
  
  static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
  {
  	struct max8952_platform_data *pd;
  	struct device_node *np = dev->of_node;
  	int ret;
  	int i;
  
  	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
7752d9640   Sachin Kamat   regulator: max895...
123
  	if (!pd)
3ff4aa95b   Tomasz Figa   regulator: max895...
124
  		return NULL;
3ff4aa95b   Tomasz Figa   regulator: max895...
125

3ff4aa95b   Tomasz Figa   regulator: max895...
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
  	if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode))
  		dev_warn(dev, "Default mode not specified, assuming 0
  ");
  
  	ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt",
  					pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode));
  	if (ret) {
  		dev_err(dev, "max8952,dvs-mode-microvolt property not specified");
  		return NULL;
  	}
  
  	for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) {
  		if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) {
  			dev_err(dev, "DVS voltage %d out of range
  ", i);
  			return NULL;
  		}
  		pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000;
  	}
  
  	if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq))
  		dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz
  ");
  
  	if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed))
  		dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us
  ");
072e78b12   Javier Martinez Canillas   regulator: of: Ad...
153
  	pd->reg_data = of_get_regulator_init_data(dev, np, &regulator);
3ff4aa95b   Tomasz Figa   regulator: max895...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	if (!pd->reg_data) {
  		dev_err(dev, "Failed to parse regulator init data
  ");
  		return NULL;
  	}
  
  	return pd;
  }
  #else
  static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
  {
  	return NULL;
  }
  #endif
a5023574d   Bill Pemberton   regulator: remove...
168
  static int max8952_pmic_probe(struct i2c_client *client,
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
169
170
  		const struct i2c_device_id *i2c_id)
  {
6b96092a6   Wolfram Sang   regulator: max895...
171
  	struct i2c_adapter *adapter = client->adapter;
dff91d0b7   Jingoo Han   regulator: use de...
172
  	struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
c172708d3   Mark Brown   regulator: core: ...
173
  	struct regulator_config config = { };
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
174
  	struct max8952_data *max8952;
b874f41c6   Krzysztof Kozlowski   regulator: max895...
175
  	struct regulator_dev *rdev;
d7a261c2d   Linus Walleij   regulator: max895...
176
177
  	struct gpio_desc *gpiod;
  	enum gpiod_flags gflags;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
178

fd742eaab   Linus Walleij   regulator: max895...
179
  	int ret = 0;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
180

3ff4aa95b   Tomasz Figa   regulator: max895...
181
182
  	if (client->dev.of_node)
  		pdata = max8952_parse_dt(&client->dev);
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
183
184
185
186
187
188
189
190
  	if (!pdata) {
  		dev_err(&client->dev, "Require the platform data
  ");
  		return -EINVAL;
  	}
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
  		return -EIO;
372de4aa5   Axel Lin   regulator: max895...
191
192
  	max8952 = devm_kzalloc(&client->dev, sizeof(struct max8952_data),
  			       GFP_KERNEL);
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
193
194
195
196
  	if (!max8952)
  		return -ENOMEM;
  
  	max8952->client = client;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
197
  	max8952->pdata = pdata;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
198

b874f41c6   Krzysztof Kozlowski   regulator: max895...
199
  	config.dev = &client->dev;
3ec6eb9cc   Tomasz Figa   regulator: max895...
200
  	config.init_data = pdata->reg_data;
c172708d3   Mark Brown   regulator: core: ...
201
  	config.driver_data = max8952;
71622e15d   Axel Lin   regulator: max895...
202
  	config.of_node = client->dev.of_node;
c172708d3   Mark Brown   regulator: core: ...
203

3ec6eb9cc   Tomasz Figa   regulator: max895...
204
  	if (pdata->reg_data->constraints.boot_on)
d7a261c2d   Linus Walleij   regulator: max895...
205
206
207
  		gflags = GPIOD_OUT_HIGH;
  	else
  		gflags = GPIOD_OUT_LOW;
63239e4bf   Linus Walleij   regulator: Fetch ...
208
  	gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
894077d5c   Linus Walleij   regulator: max895...
209
210
211
212
213
214
215
  	/*
  	 * Do not use devm* here: the regulator core takes over the
  	 * lifecycle management of the GPIO descriptor.
  	 */
  	gpiod = gpiod_get_optional(&client->dev,
  				   "max8952,en",
  				   gflags);
d7a261c2d   Linus Walleij   regulator: max895...
216
217
218
219
  	if (IS_ERR(gpiod))
  		return PTR_ERR(gpiod);
  	if (gpiod)
  		config.ena_gpiod = gpiod;
b669e0adb   Axel Lin   regulator: max895...
220

b874f41c6   Krzysztof Kozlowski   regulator: max895...
221
  	rdev = devm_regulator_register(&client->dev, &regulator, &config);
b874f41c6   Krzysztof Kozlowski   regulator: max895...
222
223
224
225
  	if (IS_ERR(rdev)) {
  		ret = PTR_ERR(rdev);
  		dev_err(&client->dev, "regulator init failed (%d)
  ", ret);
372de4aa5   Axel Lin   regulator: max895...
226
  		return ret;
da05738e9   Axel Lin   regulator: max895...
227
  	}
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
228

c8237f01d   Axel Lin   regulator: max895...
229
230
  	max8952->vid0 = pdata->default_mode & 0x1;
  	max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
231

fd742eaab   Linus Walleij   regulator: max895...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  	/* Fetch vid0 and vid1 GPIOs if available */
  	gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
  	max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev,
  							    "max8952,vid",
  							    0, gflags);
  	if (IS_ERR(max8952->vid0_gpiod))
  		return PTR_ERR(max8952->vid0_gpiod);
  	gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
  	max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev,
  							    "max8952,vid",
  							    1, gflags);
  	if (IS_ERR(max8952->vid1_gpiod))
  		return PTR_ERR(max8952->vid1_gpiod);
  
  	/* If either VID GPIO is missing just disable this */
  	if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
b874f41c6   Krzysztof Kozlowski   regulator: max895...
248
  		dev_warn(&client->dev, "VID0/1 gpio invalid: "
fd742eaab   Linus Walleij   regulator: max895...
249
250
  			 "DVS not available.
  ");
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
251
252
  		max8952->vid0 = 0;
  		max8952->vid1 = 0;
fd742eaab   Linus Walleij   regulator: max895...
253
254
255
256
257
  		/* Make sure if we have any descriptors they get set to low */
  		if (max8952->vid0_gpiod)
  			gpiod_set_value(max8952->vid0_gpiod, 0);
  		if (max8952->vid1_gpiod)
  			gpiod_set_value(max8952->vid1_gpiod, 0);
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
258
259
260
  
  		/* Disable Pulldown of EN only */
  		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
b874f41c6   Krzysztof Kozlowski   regulator: max895...
261
  		dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  				" do not have proper controls.
  ");
  	} else {
  		/*
  		 * Disable Pulldown on EN, VID0, VID1 to reduce
  		 * leakage current of MAX8952 assuming that MAX8952
  		 * is turned on (EN==1). Note that without having VID0/1
  		 * properly connected, turning pulldown off can be
  		 * problematic. Thus, turn this off only when they are
  		 * controllable by GPIO.
  		 */
  		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0);
  	}
  
  	max8952_write_reg(max8952, MAX8952_REG_MODE0,
  			(max8952_read_reg(max8952,
  					  MAX8952_REG_MODE0) & 0xC0) |
  			(pdata->dvs_mode[0] & 0x3F));
  	max8952_write_reg(max8952, MAX8952_REG_MODE1,
  			(max8952_read_reg(max8952,
  					  MAX8952_REG_MODE1) & 0xC0) |
  			(pdata->dvs_mode[1] & 0x3F));
  	max8952_write_reg(max8952, MAX8952_REG_MODE2,
  			(max8952_read_reg(max8952,
  					  MAX8952_REG_MODE2) & 0xC0) |
  			(pdata->dvs_mode[2] & 0x3F));
  	max8952_write_reg(max8952, MAX8952_REG_MODE3,
  			(max8952_read_reg(max8952,
  					  MAX8952_REG_MODE3) & 0xC0) |
  			(pdata->dvs_mode[3] & 0x3F));
  
  	max8952_write_reg(max8952, MAX8952_REG_SYNC,
  			(max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) |
  			((pdata->sync_freq & 0x3) << 6));
  	max8952_write_reg(max8952, MAX8952_REG_RAMP,
  			(max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) |
  			((pdata->ramp_speed & 0x7) << 5));
  
  	i2c_set_clientdata(client, max8952);
da05738e9   Axel Lin   regulator: max895...
301
  	return 0;
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
302
  }
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
303
304
305
306
307
308
309
310
  static const struct i2c_device_id max8952_ids[] = {
  	{ "max8952", 0 },
  	{ },
  };
  MODULE_DEVICE_TABLE(i2c, max8952_ids);
  
  static struct i2c_driver max8952_pmic_driver = {
  	.probe		= max8952_pmic_probe,
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
311
312
  	.driver		= {
  		.name	= "max8952",
3ff4aa95b   Tomasz Figa   regulator: max895...
313
  		.of_match_table = of_match_ptr(max8952_dt_match),
202f4f53e   MyungJoo Ham   MAX8952 PMIC Driv...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  	},
  	.id_table	= max8952_ids,
  };
  
  static int __init max8952_pmic_init(void)
  {
  	return i2c_add_driver(&max8952_pmic_driver);
  }
  subsys_initcall(max8952_pmic_init);
  
  static void __exit max8952_pmic_exit(void)
  {
  	i2c_del_driver(&max8952_pmic_driver);
  }
  module_exit(max8952_pmic_exit);
  
  MODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver");
  MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
  MODULE_LICENSE("GPL");