xref: /linux/drivers/regulator/max8952.c (revision a266ef69b890f099069cf51bb40572611c435a54)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * max8952.c - Voltage and current regulation for the Maxim 8952
4  *
5  * Copyright (C) 2010 Samsung Electronics
6  * MyungJoo Ham <myungjoo.ham@samsung.com>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/i2c.h>
12 #include <linux/err.h>
13 #include <linux/platform_device.h>
14 #include <linux/regulator/driver.h>
15 #include <linux/regulator/max8952.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/io.h>
18 #include <linux/of.h>
19 #include <linux/regulator/of_regulator.h>
20 #include <linux/slab.h>
21 
22 /* Registers */
23 enum {
24 	MAX8952_REG_MODE0,
25 	MAX8952_REG_MODE1,
26 	MAX8952_REG_MODE2,
27 	MAX8952_REG_MODE3,
28 	MAX8952_REG_CONTROL,
29 	MAX8952_REG_SYNC,
30 	MAX8952_REG_RAMP,
31 	MAX8952_REG_CHIP_ID1,
32 	MAX8952_REG_CHIP_ID2,
33 };
34 
35 struct max8952_data {
36 	struct i2c_client	*client;
37 	struct max8952_platform_data *pdata;
38 	struct gpio_desc *vid0_gpiod;
39 	struct gpio_desc *vid1_gpiod;
40 	bool vid0;
41 	bool vid1;
42 };
43 
44 static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
45 {
46 	int ret = i2c_smbus_read_byte_data(max8952->client, reg);
47 
48 	if (ret > 0)
49 		ret &= 0xff;
50 
51 	return ret;
52 }
53 
54 static int max8952_write_reg(struct max8952_data *max8952,
55 		u8 reg, u8 value)
56 {
57 	return i2c_smbus_write_byte_data(max8952->client, reg, value);
58 }
59 
60 static int max8952_list_voltage(struct regulator_dev *rdev,
61 		unsigned int selector)
62 {
63 	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
64 
65 	if (rdev_get_id(rdev) != 0)
66 		return -EINVAL;
67 
68 	return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000;
69 }
70 
71 static int max8952_get_voltage_sel(struct regulator_dev *rdev)
72 {
73 	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
74 	u8 vid = 0;
75 
76 	if (max8952->vid0)
77 		vid += 1;
78 	if (max8952->vid1)
79 		vid += 2;
80 
81 	return vid;
82 }
83 
84 static int max8952_set_voltage_sel(struct regulator_dev *rdev,
85 				   unsigned selector)
86 {
87 	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
88 
89 	if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
90 		/* DVS not supported */
91 		return -EPERM;
92 	}
93 
94 	max8952->vid0 = selector & 0x1;
95 	max8952->vid1 = (selector >> 1) & 0x1;
96 	gpiod_set_value(max8952->vid0_gpiod, max8952->vid0);
97 	gpiod_set_value(max8952->vid1_gpiod, max8952->vid1);
98 
99 	return 0;
100 }
101 
102 static const struct regulator_ops max8952_ops = {
103 	.list_voltage		= max8952_list_voltage,
104 	.get_voltage_sel	= max8952_get_voltage_sel,
105 	.set_voltage_sel	= max8952_set_voltage_sel,
106 };
107 
108 static const struct regulator_desc regulator = {
109 	.name		= "MAX8952_VOUT",
110 	.id		= 0,
111 	.n_voltages	= MAX8952_NUM_DVS_MODE,
112 	.ops		= &max8952_ops,
113 	.type		= REGULATOR_VOLTAGE,
114 	.owner		= THIS_MODULE,
115 };
116 
117 #ifdef CONFIG_OF
118 static const struct of_device_id max8952_dt_match[] = {
119 	{ .compatible = "maxim,max8952" },
120 	{},
121 };
122 MODULE_DEVICE_TABLE(of, max8952_dt_match);
123 
124 static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
125 {
126 	struct max8952_platform_data *pd;
127 	struct device_node *np = dev->of_node;
128 	int ret;
129 	int i;
130 
131 	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
132 	if (!pd)
133 		return NULL;
134 
135 	if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode))
136 		dev_warn(dev, "Default mode not specified, assuming 0\n");
137 
138 	ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt",
139 					pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode));
140 	if (ret) {
141 		dev_err(dev, "max8952,dvs-mode-microvolt property not specified");
142 		return NULL;
143 	}
144 
145 	for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) {
146 		if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) {
147 			dev_err(dev, "DVS voltage %d out of range\n", i);
148 			return NULL;
149 		}
150 		pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000;
151 	}
152 
153 	if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq))
154 		dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz\n");
155 
156 	if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed))
157 		dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n");
158 
159 	pd->reg_data = of_get_regulator_init_data(dev, np, &regulator);
160 	if (!pd->reg_data) {
161 		dev_err(dev, "Failed to parse regulator init data\n");
162 		return NULL;
163 	}
164 
165 	return pd;
166 }
167 #else
168 static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
169 {
170 	return NULL;
171 }
172 #endif
173 
174 static int max8952_pmic_probe(struct i2c_client *client)
175 {
176 	struct i2c_adapter *adapter = client->adapter;
177 	struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
178 	struct regulator_config config = { };
179 	struct max8952_data *max8952;
180 	struct regulator_dev *rdev;
181 	struct gpio_desc *gpiod;
182 	enum gpiod_flags gflags;
183 
184 	int ret = 0;
185 
186 	if (client->dev.of_node)
187 		pdata = max8952_parse_dt(&client->dev);
188 
189 	if (!pdata) {
190 		dev_err(&client->dev, "Require the platform data\n");
191 		return -EINVAL;
192 	}
193 
194 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
195 		return -EIO;
196 
197 	max8952 = devm_kzalloc(&client->dev, sizeof(struct max8952_data),
198 			       GFP_KERNEL);
199 	if (!max8952)
200 		return -ENOMEM;
201 
202 	max8952->client = client;
203 	max8952->pdata = pdata;
204 
205 	config.dev = &client->dev;
206 	config.init_data = pdata->reg_data;
207 	config.driver_data = max8952;
208 	config.of_node = client->dev.of_node;
209 
210 	if (pdata->reg_data->constraints.boot_on)
211 		gflags = GPIOD_OUT_HIGH;
212 	else
213 		gflags = GPIOD_OUT_LOW;
214 	gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
215 	/*
216 	 * Do not use devm* here: the regulator core takes over the
217 	 * lifecycle management of the GPIO descriptor.
218 	 */
219 	gpiod = gpiod_get_optional(&client->dev,
220 				   "max8952,en",
221 				   gflags);
222 	if (IS_ERR(gpiod))
223 		return PTR_ERR(gpiod);
224 	if (gpiod)
225 		config.ena_gpiod = gpiod;
226 
227 	rdev = devm_regulator_register(&client->dev, &regulator, &config);
228 	if (IS_ERR(rdev)) {
229 		ret = PTR_ERR(rdev);
230 		dev_err(&client->dev, "regulator init failed (%d)\n", ret);
231 		return ret;
232 	}
233 
234 	max8952->vid0 = pdata->default_mode & 0x1;
235 	max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
236 
237 	/* Fetch vid0 and vid1 GPIOs if available */
238 	gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
239 	max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev,
240 							    "max8952,vid",
241 							    0, gflags);
242 	if (IS_ERR(max8952->vid0_gpiod))
243 		return PTR_ERR(max8952->vid0_gpiod);
244 	gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
245 	max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev,
246 							    "max8952,vid",
247 							    1, gflags);
248 	if (IS_ERR(max8952->vid1_gpiod))
249 		return PTR_ERR(max8952->vid1_gpiod);
250 
251 	/* If either VID GPIO is missing just disable this */
252 	if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) {
253 		dev_warn(&client->dev, "VID0/1 gpio invalid: "
254 			 "DVS not available.\n");
255 		max8952->vid0 = 0;
256 		max8952->vid1 = 0;
257 		/* Make sure if we have any descriptors they get set to low */
258 		if (max8952->vid0_gpiod)
259 			gpiod_set_value(max8952->vid0_gpiod, 0);
260 		if (max8952->vid1_gpiod)
261 			gpiod_set_value(max8952->vid1_gpiod, 0);
262 
263 		/* Disable Pulldown of EN only */
264 		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
265 
266 		dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"
267 				" do not have proper controls.\n");
268 	} else {
269 		/*
270 		 * Disable Pulldown on EN, VID0, VID1 to reduce
271 		 * leakage current of MAX8952 assuming that MAX8952
272 		 * is turned on (EN==1). Note that without having VID0/1
273 		 * properly connected, turning pulldown off can be
274 		 * problematic. Thus, turn this off only when they are
275 		 * controllable by GPIO.
276 		 */
277 		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0);
278 	}
279 
280 	max8952_write_reg(max8952, MAX8952_REG_MODE0,
281 			(max8952_read_reg(max8952,
282 					  MAX8952_REG_MODE0) & 0xC0) |
283 			(pdata->dvs_mode[0] & 0x3F));
284 	max8952_write_reg(max8952, MAX8952_REG_MODE1,
285 			(max8952_read_reg(max8952,
286 					  MAX8952_REG_MODE1) & 0xC0) |
287 			(pdata->dvs_mode[1] & 0x3F));
288 	max8952_write_reg(max8952, MAX8952_REG_MODE2,
289 			(max8952_read_reg(max8952,
290 					  MAX8952_REG_MODE2) & 0xC0) |
291 			(pdata->dvs_mode[2] & 0x3F));
292 	max8952_write_reg(max8952, MAX8952_REG_MODE3,
293 			(max8952_read_reg(max8952,
294 					  MAX8952_REG_MODE3) & 0xC0) |
295 			(pdata->dvs_mode[3] & 0x3F));
296 
297 	max8952_write_reg(max8952, MAX8952_REG_SYNC,
298 			(max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) |
299 			((pdata->sync_freq & 0x3) << 6));
300 	max8952_write_reg(max8952, MAX8952_REG_RAMP,
301 			(max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) |
302 			((pdata->ramp_speed & 0x7) << 5));
303 
304 	i2c_set_clientdata(client, max8952);
305 
306 	return 0;
307 }
308 
309 static const struct i2c_device_id max8952_ids[] = {
310 	{ "max8952", 0 },
311 	{ },
312 };
313 MODULE_DEVICE_TABLE(i2c, max8952_ids);
314 
315 static struct i2c_driver max8952_pmic_driver = {
316 	.probe_new	= max8952_pmic_probe,
317 	.driver		= {
318 		.name	= "max8952",
319 		.of_match_table = of_match_ptr(max8952_dt_match),
320 	},
321 	.id_table	= max8952_ids,
322 };
323 
324 static int __init max8952_pmic_init(void)
325 {
326 	return i2c_add_driver(&max8952_pmic_driver);
327 }
328 subsys_initcall(max8952_pmic_init);
329 
330 static void __exit max8952_pmic_exit(void)
331 {
332 	i2c_del_driver(&max8952_pmic_driver);
333 }
334 module_exit(max8952_pmic_exit);
335 
336 MODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver");
337 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
338 MODULE_LICENSE("GPL");
339