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