xref: /linux/drivers/regulator/max77838-regulator.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*6a1f303cSIvaylo Ivanov // SPDX-License-Identifier: GPL-2.0-or-later
2*6a1f303cSIvaylo Ivanov //
3*6a1f303cSIvaylo Ivanov // regulator driver for Maxim MAX77838
4*6a1f303cSIvaylo Ivanov //
5*6a1f303cSIvaylo Ivanov // based on max77826-regulator.c
6*6a1f303cSIvaylo Ivanov //
7*6a1f303cSIvaylo Ivanov // Copyright (c) 2025, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
8*6a1f303cSIvaylo Ivanov 
9*6a1f303cSIvaylo Ivanov #include <linux/kernel.h>
10*6a1f303cSIvaylo Ivanov #include <linux/module.h>
11*6a1f303cSIvaylo Ivanov #include <linux/init.h>
12*6a1f303cSIvaylo Ivanov #include <linux/err.h>
13*6a1f303cSIvaylo Ivanov #include <linux/of.h>
14*6a1f303cSIvaylo Ivanov #include <linux/platform_device.h>
15*6a1f303cSIvaylo Ivanov #include <linux/regulator/driver.h>
16*6a1f303cSIvaylo Ivanov #include <linux/regulator/of_regulator.h>
17*6a1f303cSIvaylo Ivanov #include <linux/i2c.h>
18*6a1f303cSIvaylo Ivanov #include <linux/regmap.h>
19*6a1f303cSIvaylo Ivanov 
20*6a1f303cSIvaylo Ivanov enum max77838_registers {
21*6a1f303cSIvaylo Ivanov 	MAX77838_REG_DEVICE_ID = 0x00,
22*6a1f303cSIvaylo Ivanov 	MAX77838_REG_TOPSYS_STAT,
23*6a1f303cSIvaylo Ivanov 	MAX77838_REG_STAT,
24*6a1f303cSIvaylo Ivanov 	MAX77838_REG_EN,
25*6a1f303cSIvaylo Ivanov 	MAX77838_REG_GPIO_PD_CTRL,
26*6a1f303cSIvaylo Ivanov 	MAX77838_REG_UVLO_CFG1,
27*6a1f303cSIvaylo Ivanov 	/* 0x06 - 0x0B: reserved */
28*6a1f303cSIvaylo Ivanov 	MAX77838_REG_I2C_CFG = 0x0C,
29*6a1f303cSIvaylo Ivanov 	/* 0x0D - 0x0F: reserved */
30*6a1f303cSIvaylo Ivanov 	MAX77838_REG_LDO1_CFG = 0x10,
31*6a1f303cSIvaylo Ivanov 	MAX77838_REG_LDO2_CFG,
32*6a1f303cSIvaylo Ivanov 	MAX77838_REG_LDO3_CFG,
33*6a1f303cSIvaylo Ivanov 	MAX77838_REG_LDO4_CFG,
34*6a1f303cSIvaylo Ivanov 	/* 0x14 - 0x1F: reserved */
35*6a1f303cSIvaylo Ivanov 	MAX77838_REG_BUCK_CFG1 = 0x20,
36*6a1f303cSIvaylo Ivanov 	MAX77838_REG_BUCK_VOUT,
37*6a1f303cSIvaylo Ivanov };
38*6a1f303cSIvaylo Ivanov 
39*6a1f303cSIvaylo Ivanov enum max77838_regulators {
40*6a1f303cSIvaylo Ivanov 	MAX77838_LDO1 = 0,
41*6a1f303cSIvaylo Ivanov 	MAX77838_LDO2,
42*6a1f303cSIvaylo Ivanov 	MAX77838_LDO3,
43*6a1f303cSIvaylo Ivanov 	MAX77838_LDO4,
44*6a1f303cSIvaylo Ivanov 	MAX77838_BUCK,
45*6a1f303cSIvaylo Ivanov 	MAX77838_MAX_REGULATORS,
46*6a1f303cSIvaylo Ivanov };
47*6a1f303cSIvaylo Ivanov 
48*6a1f303cSIvaylo Ivanov #define MAX77838_MASK_LDO		0x7f
49*6a1f303cSIvaylo Ivanov #define MAX77838_MASK_BUCK		0xff
50*6a1f303cSIvaylo Ivanov 
51*6a1f303cSIvaylo Ivanov #define MAX77838_LDO1_EN		BIT(0)
52*6a1f303cSIvaylo Ivanov #define MAX77838_LDO2_EN		BIT(1)
53*6a1f303cSIvaylo Ivanov #define MAX77838_LDO3_EN		BIT(2)
54*6a1f303cSIvaylo Ivanov #define MAX77838_LDO4_EN		BIT(3)
55*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_EN		BIT(4)
56*6a1f303cSIvaylo Ivanov 
57*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_AD		BIT(3)
58*6a1f303cSIvaylo Ivanov #define MAX77838_LDO_AD			BIT(7)
59*6a1f303cSIvaylo Ivanov 
60*6a1f303cSIvaylo Ivanov #define MAX77838_LDO_VOLT_MIN		600000
61*6a1f303cSIvaylo Ivanov #define MAX77838_LDO_VOLT_MAX		3775000
62*6a1f303cSIvaylo Ivanov #define MAX77838_LDO_VOLT_STEP		25000
63*6a1f303cSIvaylo Ivanov 
64*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_VOLT_MIN		500000
65*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_VOLT_MAX		2093750
66*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_VOLT_STEP		6250
67*6a1f303cSIvaylo Ivanov 
68*6a1f303cSIvaylo Ivanov #define MAX77838_VOLT_RANGE(_type)				\
69*6a1f303cSIvaylo Ivanov 	((MAX77838_ ## _type ## _VOLT_MAX -			\
70*6a1f303cSIvaylo Ivanov 	  MAX77838_ ## _type ## _VOLT_MIN) /			\
71*6a1f303cSIvaylo Ivanov 	  MAX77838_ ## _type ## _VOLT_STEP + 1)
72*6a1f303cSIvaylo Ivanov 
73*6a1f303cSIvaylo Ivanov #define MAX77838_LDO(_id)							\
74*6a1f303cSIvaylo Ivanov 	[MAX77838_LDO ## _id] = {						\
75*6a1f303cSIvaylo Ivanov 		.id = MAX77838_LDO ## _id,					\
76*6a1f303cSIvaylo Ivanov 		.name = "ldo"#_id,						\
77*6a1f303cSIvaylo Ivanov 		.of_match = of_match_ptr("ldo"#_id),				\
78*6a1f303cSIvaylo Ivanov 		.regulators_node = "regulators",				\
79*6a1f303cSIvaylo Ivanov 		.ops = &max77838_regulator_ops,					\
80*6a1f303cSIvaylo Ivanov 		.min_uV = MAX77838_LDO_VOLT_MIN,				\
81*6a1f303cSIvaylo Ivanov 		.uV_step = MAX77838_LDO_VOLT_STEP,				\
82*6a1f303cSIvaylo Ivanov 		.n_voltages = MAX77838_VOLT_RANGE(LDO),				\
83*6a1f303cSIvaylo Ivanov 		.enable_reg = MAX77838_REG_EN,					\
84*6a1f303cSIvaylo Ivanov 		.enable_mask = MAX77838_LDO ## _id ## _EN,			\
85*6a1f303cSIvaylo Ivanov 		.vsel_reg = MAX77838_REG_LDO ## _id ## _CFG,			\
86*6a1f303cSIvaylo Ivanov 		.vsel_mask = MAX77838_MASK_LDO,					\
87*6a1f303cSIvaylo Ivanov 		.active_discharge_off = 0,					\
88*6a1f303cSIvaylo Ivanov 		.active_discharge_on = MAX77838_LDO_AD,				\
89*6a1f303cSIvaylo Ivanov 		.active_discharge_mask = MAX77838_LDO_AD,			\
90*6a1f303cSIvaylo Ivanov 		.active_discharge_reg = MAX77838_REG_LDO ## _id ## _CFG,	\
91*6a1f303cSIvaylo Ivanov 		.owner = THIS_MODULE,						\
92*6a1f303cSIvaylo Ivanov 	}
93*6a1f303cSIvaylo Ivanov 
94*6a1f303cSIvaylo Ivanov #define MAX77838_BUCK_DESC					\
95*6a1f303cSIvaylo Ivanov 	[MAX77838_BUCK] = {					\
96*6a1f303cSIvaylo Ivanov 		.id = MAX77838_BUCK,				\
97*6a1f303cSIvaylo Ivanov 		.name = "buck",					\
98*6a1f303cSIvaylo Ivanov 		.of_match = of_match_ptr("buck"),		\
99*6a1f303cSIvaylo Ivanov 		.regulators_node = "regulators",		\
100*6a1f303cSIvaylo Ivanov 		.ops = &max77838_regulator_ops,			\
101*6a1f303cSIvaylo Ivanov 		.min_uV = MAX77838_BUCK_VOLT_MIN,		\
102*6a1f303cSIvaylo Ivanov 		.uV_step = MAX77838_BUCK_VOLT_STEP,		\
103*6a1f303cSIvaylo Ivanov 		.n_voltages = MAX77838_VOLT_RANGE(BUCK),	\
104*6a1f303cSIvaylo Ivanov 		.enable_reg = MAX77838_REG_EN,			\
105*6a1f303cSIvaylo Ivanov 		.enable_mask = MAX77838_BUCK_EN,		\
106*6a1f303cSIvaylo Ivanov 		.vsel_reg = MAX77838_REG_BUCK_VOUT,		\
107*6a1f303cSIvaylo Ivanov 		.vsel_mask = MAX77838_MASK_BUCK,		\
108*6a1f303cSIvaylo Ivanov 		.active_discharge_off = 0,			\
109*6a1f303cSIvaylo Ivanov 		.active_discharge_on = MAX77838_BUCK_AD,	\
110*6a1f303cSIvaylo Ivanov 		.active_discharge_mask = MAX77838_BUCK_AD,	\
111*6a1f303cSIvaylo Ivanov 		.active_discharge_reg = MAX77838_REG_BUCK_CFG1,	\
112*6a1f303cSIvaylo Ivanov 		.owner = THIS_MODULE,				\
113*6a1f303cSIvaylo Ivanov 	}
114*6a1f303cSIvaylo Ivanov 
115*6a1f303cSIvaylo Ivanov struct max77838_regulator_info {
116*6a1f303cSIvaylo Ivanov 	struct regmap *regmap;
117*6a1f303cSIvaylo Ivanov };
118*6a1f303cSIvaylo Ivanov 
119*6a1f303cSIvaylo Ivanov static const struct regmap_config max77838_regmap_config = {
120*6a1f303cSIvaylo Ivanov 	.reg_bits = 8,
121*6a1f303cSIvaylo Ivanov 	.val_bits = 8,
122*6a1f303cSIvaylo Ivanov 	.max_register = MAX77838_REG_BUCK_VOUT,
123*6a1f303cSIvaylo Ivanov };
124*6a1f303cSIvaylo Ivanov 
125*6a1f303cSIvaylo Ivanov static const struct regulator_ops max77838_regulator_ops = {
126*6a1f303cSIvaylo Ivanov 	.enable			= regulator_enable_regmap,
127*6a1f303cSIvaylo Ivanov 	.disable		= regulator_disable_regmap,
128*6a1f303cSIvaylo Ivanov 	.is_enabled		= regulator_is_enabled_regmap,
129*6a1f303cSIvaylo Ivanov 	.list_voltage		= regulator_list_voltage_linear,
130*6a1f303cSIvaylo Ivanov 	.map_voltage		= regulator_map_voltage_linear,
131*6a1f303cSIvaylo Ivanov 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
132*6a1f303cSIvaylo Ivanov 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
133*6a1f303cSIvaylo Ivanov 	.set_active_discharge	= regulator_set_active_discharge_regmap,
134*6a1f303cSIvaylo Ivanov };
135*6a1f303cSIvaylo Ivanov 
136*6a1f303cSIvaylo Ivanov static const struct regulator_desc max77838_regulators_desc[] = {
137*6a1f303cSIvaylo Ivanov 	MAX77838_LDO(1),
138*6a1f303cSIvaylo Ivanov 	MAX77838_LDO(2),
139*6a1f303cSIvaylo Ivanov 	MAX77838_LDO(3),
140*6a1f303cSIvaylo Ivanov 	MAX77838_LDO(4),
141*6a1f303cSIvaylo Ivanov 	MAX77838_BUCK_DESC,
142*6a1f303cSIvaylo Ivanov };
143*6a1f303cSIvaylo Ivanov 
144*6a1f303cSIvaylo Ivanov static int max77838_read_device_id(struct regmap *regmap, struct device *dev)
145*6a1f303cSIvaylo Ivanov {
146*6a1f303cSIvaylo Ivanov 	unsigned int device_id;
147*6a1f303cSIvaylo Ivanov 	int ret;
148*6a1f303cSIvaylo Ivanov 
149*6a1f303cSIvaylo Ivanov 	ret = regmap_read(regmap, MAX77838_REG_DEVICE_ID, &device_id);
150*6a1f303cSIvaylo Ivanov 	if (!ret)
151*6a1f303cSIvaylo Ivanov 		dev_dbg(dev, "DEVICE_ID: 0x%x\n", device_id);
152*6a1f303cSIvaylo Ivanov 
153*6a1f303cSIvaylo Ivanov 	return ret;
154*6a1f303cSIvaylo Ivanov }
155*6a1f303cSIvaylo Ivanov 
156*6a1f303cSIvaylo Ivanov static int max77838_i2c_probe(struct i2c_client *client)
157*6a1f303cSIvaylo Ivanov {
158*6a1f303cSIvaylo Ivanov 	struct device *dev = &client->dev;
159*6a1f303cSIvaylo Ivanov 	struct max77838_regulator_info *info;
160*6a1f303cSIvaylo Ivanov 	struct regulator_config config = {};
161*6a1f303cSIvaylo Ivanov 	struct regulator_dev *rdev;
162*6a1f303cSIvaylo Ivanov 	struct regmap *regmap;
163*6a1f303cSIvaylo Ivanov 	int i;
164*6a1f303cSIvaylo Ivanov 
165*6a1f303cSIvaylo Ivanov 	info = devm_kzalloc(dev, sizeof(struct max77838_regulator_info),
166*6a1f303cSIvaylo Ivanov 			    GFP_KERNEL);
167*6a1f303cSIvaylo Ivanov 	if (!info)
168*6a1f303cSIvaylo Ivanov 		return -ENOMEM;
169*6a1f303cSIvaylo Ivanov 
170*6a1f303cSIvaylo Ivanov 	regmap = devm_regmap_init_i2c(client, &max77838_regmap_config);
171*6a1f303cSIvaylo Ivanov 	if (IS_ERR(regmap)) {
172*6a1f303cSIvaylo Ivanov 		dev_err(dev, "Failed to allocate regmap!\n");
173*6a1f303cSIvaylo Ivanov 		return PTR_ERR(regmap);
174*6a1f303cSIvaylo Ivanov 	}
175*6a1f303cSIvaylo Ivanov 
176*6a1f303cSIvaylo Ivanov 	info->regmap = regmap;
177*6a1f303cSIvaylo Ivanov 	i2c_set_clientdata(client, info);
178*6a1f303cSIvaylo Ivanov 
179*6a1f303cSIvaylo Ivanov 	config.dev = dev;
180*6a1f303cSIvaylo Ivanov 	config.regmap = regmap;
181*6a1f303cSIvaylo Ivanov 	config.driver_data = info;
182*6a1f303cSIvaylo Ivanov 
183*6a1f303cSIvaylo Ivanov 	for (i = 0; i < MAX77838_MAX_REGULATORS; i++) {
184*6a1f303cSIvaylo Ivanov 		rdev = devm_regulator_register(dev,
185*6a1f303cSIvaylo Ivanov 					       &max77838_regulators_desc[i],
186*6a1f303cSIvaylo Ivanov 					       &config);
187*6a1f303cSIvaylo Ivanov 		if (IS_ERR(rdev)) {
188*6a1f303cSIvaylo Ivanov 			dev_err(dev, "Failed to register regulator!\n");
189*6a1f303cSIvaylo Ivanov 			return PTR_ERR(rdev);
190*6a1f303cSIvaylo Ivanov 		}
191*6a1f303cSIvaylo Ivanov 	}
192*6a1f303cSIvaylo Ivanov 
193*6a1f303cSIvaylo Ivanov 	return max77838_read_device_id(regmap, dev);
194*6a1f303cSIvaylo Ivanov }
195*6a1f303cSIvaylo Ivanov 
196*6a1f303cSIvaylo Ivanov static const struct of_device_id __maybe_unused max77838_of_match[] = {
197*6a1f303cSIvaylo Ivanov 	{ .compatible = "maxim,max77838" },
198*6a1f303cSIvaylo Ivanov 	{ /* sentinel */ }
199*6a1f303cSIvaylo Ivanov };
200*6a1f303cSIvaylo Ivanov MODULE_DEVICE_TABLE(of, max77838_of_match);
201*6a1f303cSIvaylo Ivanov 
202*6a1f303cSIvaylo Ivanov static const struct i2c_device_id max77838_id[] = {
203*6a1f303cSIvaylo Ivanov 	{ "max77838-regulator" },
204*6a1f303cSIvaylo Ivanov 	{ /* sentinel */ }
205*6a1f303cSIvaylo Ivanov };
206*6a1f303cSIvaylo Ivanov MODULE_DEVICE_TABLE(i2c, max77838_id);
207*6a1f303cSIvaylo Ivanov 
208*6a1f303cSIvaylo Ivanov static struct i2c_driver max77838_regulator_driver = {
209*6a1f303cSIvaylo Ivanov 	.driver = {
210*6a1f303cSIvaylo Ivanov 		.name = "max77838",
211*6a1f303cSIvaylo Ivanov 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
212*6a1f303cSIvaylo Ivanov 		.of_match_table = of_match_ptr(max77838_of_match),
213*6a1f303cSIvaylo Ivanov 	},
214*6a1f303cSIvaylo Ivanov 	.probe = max77838_i2c_probe,
215*6a1f303cSIvaylo Ivanov 	.id_table = max77838_id,
216*6a1f303cSIvaylo Ivanov };
217*6a1f303cSIvaylo Ivanov module_i2c_driver(max77838_regulator_driver);
218*6a1f303cSIvaylo Ivanov 
219*6a1f303cSIvaylo Ivanov MODULE_AUTHOR("Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>");
220*6a1f303cSIvaylo Ivanov MODULE_DESCRIPTION("MAX77838 PMIC regulator driver");
221*6a1f303cSIvaylo Ivanov MODULE_LICENSE("GPL");
222