Skip to content

Commit 8cf13d6

Browse files
committed
regulator: max77840: Add regulator driver for MAX77840 PMIC
Add regulator support for the MAX77840 PMIC to control voltage and current regulation. This enables proper power management features required for various submodules dependent on this regulator. Signed-off-by: joan-na-good <joan.na@analog.com>
1 parent e34ccdf commit 8cf13d6

File tree

4 files changed

+331
-0
lines changed

4 files changed

+331
-0
lines changed

drivers/regulator/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,20 @@ config REGULATOR_MAX77650
615615
Semiconductor. This device has a SIMO with three independent
616616
power rails and an LDO.
617617

618+
config REGULATOR_MAX77840
619+
tristate "Maxim Integrated MAX77840 Regulator"
620+
depends on MFD_MAX77840
621+
help
622+
Say Y here to enable support for the voltage regulators provided by
623+
the Maxim Integrated MAX77840 PMIC. This driver supports the control
624+
and monitoring of the on-chip LDOs and buck converters via the regulator
625+
framework.
626+
627+
The MAX77840 communicates over the I2C bus and is commonly used in
628+
mobile and battery-powered devices. This driver allows setting regulator
629+
voltage levels and handling regulator enable/disable through standard
630+
kernel interfaces.
631+
618632
config REGULATOR_MAX77857
619633
tristate "ADI MAX77857/MAX77831 regulator support"
620634
depends on I2C

drivers/regulator/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
8989
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
9090
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
9191
obj-$(CONFIG_REGULATOR_MAX77826) += max77826-regulator.o
92+
obj-$(CONFIG_REGULATOR_MAX77840) += max77840-regulator.o
9293
obj-$(CONFIG_REGULATOR_MAX77857) += max77857-regulator.o
9394
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
9495
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2020 Maxim Integrated Products, Inc.
4+
* Copyright (C) 2024 Analog Devices, Inc.
5+
*
6+
* Author : Analog Devices <joan.na@analog.com>
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2 as
10+
* published by the Free Software Foundation.
11+
*/
12+
13+
#define pr_fmt(fmt) "%s: " fmt, __func__
14+
15+
#include <linux/version.h>
16+
#include <linux/err.h>
17+
#include <linux/slab.h>
18+
#include <linux/platform_device.h>
19+
#include <linux/regulator/driver.h>
20+
#include <linux/regmap.h>
21+
#include <linux/mfd/max77840.h>
22+
#include <linux/regulator/max77840-regulator.h>
23+
#include <linux/module.h>
24+
#include <linux/regulator/of_regulator.h>
25+
#include <linux/of.h>
26+
27+
#ifdef __TEST_DEVICE_NODE__
28+
#include <linux/string.h>
29+
#include <linux/sysfs.h>
30+
#endif
31+
32+
#define M2SH __CONST_FFS
33+
34+
/* Register */
35+
/* Safeout */
36+
#define REG_SAFEOUTCTRL 0xC6
37+
#define BIT_SAFEOUT1 BITS(1, 0)
38+
#define BIT_ACTDISSAFEO1 BIT(4)
39+
#define BIT_ENSAFEOUT1 BIT(6)
40+
41+
struct max77840_data {
42+
struct device *dev;
43+
struct max77840_dev *iodev;
44+
struct regulator_dev *rdev;
45+
};
46+
47+
static unsigned int max77840_safeout_volt_table[] = {
48+
4850000, 4900000, 4950000, 3300000,
49+
};
50+
51+
static const struct regulator_ops max77840_safeout_ops = {
52+
.list_voltage = regulator_list_voltage_table,
53+
.map_voltage = regulator_map_voltage_ascend,
54+
.is_enabled = regulator_is_enabled_regmap,
55+
.enable = regulator_enable_regmap,
56+
.disable = regulator_disable_regmap,
57+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
58+
.set_voltage_sel = regulator_set_voltage_sel_regmap,
59+
};
60+
61+
static struct regulator_desc max77840_safeout_desc = {
62+
.name = "SAFEOUT1",
63+
.id = MAX77840_SAFEOUT1,
64+
.ops = &max77840_safeout_ops,
65+
.type = REGULATOR_VOLTAGE,
66+
.owner = THIS_MODULE,
67+
.n_voltages = ARRAY_SIZE(max77840_safeout_volt_table),
68+
.volt_table = max77840_safeout_volt_table,
69+
.vsel_reg = REG_SAFEOUTCTRL,
70+
.vsel_mask = BIT_SAFEOUT1,
71+
.enable_reg = REG_SAFEOUTCTRL,
72+
.enable_mask = BIT_ENSAFEOUT1,
73+
};
74+
75+
#ifdef CONFIG_OF
76+
static struct max77840_regulator_platform_data
77+
*max77840_regulator_parse_dt(struct device *dev)
78+
{
79+
struct device_node *np = of_find_node_by_name(NULL, "regulator");
80+
struct max77840_regulator_platform_data *pdata;
81+
82+
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
83+
if (unlikely(!pdata))
84+
return ERR_PTR(-ENOMEM);
85+
86+
if (!np) {
87+
pr_err("%s np NULL\n", __func__);
88+
pdata = ERR_PTR(-EINVAL);
89+
goto out;
90+
}
91+
92+
if (!of_node_cmp(np->name, max77840_safeout_desc.name))
93+
pdata->initdata = of_get_regulator_init_data(dev, np, &max77840_safeout_desc);
94+
95+
pdata->of_node = np;
96+
of_node_put(np);
97+
98+
out:
99+
return pdata;
100+
}
101+
#endif
102+
103+
#ifdef __TEST_DEVICE_NODE__
104+
static struct max77840_data *test_if;
105+
static ssize_t max77840_test_store(struct device *dev,
106+
struct device_attribute *attr,
107+
const char *buf, size_t size)
108+
{
109+
int ret, reg;
110+
unsigned long strval;
111+
u8 rval;
112+
char *args[3];
113+
char *sep = ",\t";
114+
char *buff = (char *)buf;
115+
struct regmap *if_regmap = test_if->iodev->regmap_pmic;
116+
117+
args[0] = strsep(&buff, sep);
118+
if (!args[0])
119+
return -2;
120+
121+
// register read
122+
args[1] = strsep(&buff, sep);
123+
if (strncmp("read", args[0], 4) == 0) {
124+
ret = kstrtoul(args[1], 0, &strval);
125+
reg = (int)strval;
126+
ret = max77840_read(if_regmap, reg, &rval);
127+
if (ret < 0)
128+
dev_err(test_if->dev, "failed to read i2c: %d @ function %s\n",
129+
ret, __func__);
130+
else
131+
dev_err(test_if->dev, "read [0x%x] = 0x%x\n", reg, rval);
132+
return size;
133+
}
134+
// register write
135+
else if (strncmp("write", args[0], 5) == 0) {
136+
ret = kstrtoul(args[1], 0, &strval);
137+
reg = (int)strval;
138+
args[2] = strsep(&buff, sep);
139+
ret = kstrtoul(args[2], 0, &strval);
140+
rval = (int)strval;
141+
ret = max77840_write(if_regmap, reg, rval);
142+
if (ret < 0)
143+
dev_err(test_if->dev, "failed to write i2c: %d @ function %s\n",
144+
ret, __func__);
145+
else
146+
dev_err(test_if->dev, "write [0x%x] = 0x%x\n", reg, rval);
147+
return size;
148+
}
149+
dev_err(test_if->dev, "Command not supported.\n");
150+
151+
return 0;
152+
}
153+
154+
static struct device_attribute max77840_attribute = {
155+
.attr = {
156+
.name = "max77840_test_if",
157+
.mode = 0x0666,
158+
},
159+
.show = NULL,
160+
.store = max77840_test_store,
161+
};
162+
163+
static int max77840_test_node(struct max77840_data *max77840)
164+
{
165+
int ret;
166+
167+
ret = sysfs_create_file(&max77840->dev->kobj, &max77840_attribute.attr);
168+
test_if = max77840;
169+
return ret;
170+
}
171+
#else
172+
static int max77840_test_node(struct max77840_data *pmic)
173+
{
174+
return 0;
175+
}
176+
#endif
177+
178+
static int max77840_regulator_probe(struct platform_device *pdev)
179+
{
180+
struct max77840_dev *iodev = dev_get_drvdata(pdev->dev.parent);
181+
struct max77840_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev);
182+
struct regulator_dev *rdev;
183+
struct max77840_data *max77840;
184+
struct regmap *regmap;
185+
struct regulator_config config;
186+
int ret, size;
187+
188+
pr_info("%s: Max77840 Regulator Driver Loading\n", __func__);
189+
190+
#ifdef CONFIG_OF
191+
pdata = max77840_regulator_parse_dt(&pdev->dev);
192+
#endif
193+
if (IS_ERR(pdata)) {
194+
pr_info("[%s:%d] !pdata\n", __FILE__, __LINE__);
195+
dev_err(pdev->dev.parent, "No platform init data supplied.\n");
196+
return PTR_ERR(pdata);
197+
}
198+
199+
max77840 = kzalloc(sizeof(*max77840), GFP_KERNEL);
200+
if (!max77840)
201+
return -ENOMEM;
202+
203+
size = sizeof(struct regulator_dev *);
204+
max77840->rdev = kzalloc(size, GFP_KERNEL);
205+
if (!max77840->rdev) {
206+
pr_info("[%s:%d] if (!max77840->rdev)\n", __FILE__, __LINE__);
207+
kfree(max77840);
208+
return -ENOMEM;
209+
}
210+
211+
rdev = max77840->rdev;
212+
max77840->dev = &pdev->dev;
213+
max77840->iodev = iodev;
214+
platform_set_drvdata(pdev, max77840);
215+
regmap = max77840->iodev->regmap_pmic;
216+
217+
pr_info("[%s:%d] for regulator\n",
218+
__FILE__,
219+
__LINE__);
220+
221+
config.dev = &pdev->dev;
222+
config.driver_data = max77840;
223+
config.init_data = pdata->initdata;
224+
config.of_node = pdata->of_node;
225+
config.regmap = regmap;
226+
rdev = devm_regulator_register(&pdev->dev, &max77840_safeout_desc, &config);
227+
228+
if (IS_ERR(rdev)) {
229+
ret = PTR_ERR(rdev);
230+
dev_err(max77840->dev, "regulator init failed!\n");
231+
rdev = NULL;
232+
goto err;
233+
}
234+
235+
max77840_test_node(max77840);
236+
return 0;
237+
err:
238+
pr_info("[%s:%d] err:\n", __FILE__, __LINE__);
239+
pr_info("[%s:%d] err_alloc\n", __FILE__, __LINE__);
240+
kfree(max77840->rdev);
241+
kfree(max77840);
242+
243+
return ret;
244+
}
245+
246+
static int max77840_regulator_remove(struct platform_device *pdev)
247+
{
248+
struct max77840_data *max77840 = platform_get_drvdata(pdev);
249+
struct regulator_dev *rdev = max77840->rdev;
250+
251+
regulator_unregister(rdev);
252+
kfree(max77840->rdev);
253+
kfree(max77840);
254+
255+
return 0;
256+
}
257+
258+
static const struct platform_device_id max77840_regulator_id[] = {
259+
{"max77840-regulator", 0},
260+
{},
261+
};
262+
263+
MODULE_DEVICE_TABLE(platform, max77840_regulator_id);
264+
265+
static struct platform_driver max77840_regulator_driver = {
266+
.driver = {
267+
.name = MAX77840_REGULATOR_NAME,
268+
},
269+
.probe = max77840_regulator_probe,
270+
.remove = max77840_regulator_remove,
271+
.id_table = max77840_regulator_id,
272+
};
273+
274+
static int __init max77840_regulator_init(void)
275+
{
276+
return platform_driver_register(&max77840_regulator_driver);
277+
}
278+
279+
static void __exit max77840_regulator_exit(void)
280+
{
281+
platform_driver_unregister(&max77840_regulator_driver);
282+
}
283+
284+
subsys_initcall(max77840_regulator_init);
285+
module_exit(max77840_regulator_exit);
286+
287+
MODULE_DESCRIPTION("MAXIM 77840 Regulator Driver");
288+
MODULE_AUTHOR("joan.na@analog.com");
289+
MODULE_LICENSE("GPL");
290+
MODULE_VERSION("1.0");
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2019 Maxim Integrated Products, Inc.
4+
* Copyright (C) 2024 Analog Devices, Inc.
5+
*
6+
* Author : Analog Devices <joan.na@analog.com>
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2 as
10+
* published by the Free Software Foundation.
11+
*/
12+
13+
#ifndef __LINUX_MAX77840_REGULATOR_H
14+
#define __LINUX_MAX77840_REGULATOR_H
15+
16+
struct max77840_regulator_platform_data {
17+
struct regulator_init_data *initdata;
18+
struct device_node *of_node;
19+
};
20+
21+
enum max77840_regulators {
22+
MAX77840_SAFEOUT1 = 0,
23+
MAX77840_REG_MAX,
24+
};
25+
26+
#endif

0 commit comments

Comments
 (0)