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 20 enum 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 39 enum 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 115 struct max77838_regulator_info { 116 struct regmap *regmap; 117 }; 118 119 static const struct regmap_config max77838_regmap_config = { 120 .reg_bits = 8, 121 .val_bits = 8, 122 .max_register = MAX77838_REG_BUCK_VOUT, 123 }; 124 125 static 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 136 static 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 144 static 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 156 static 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 196 static const struct of_device_id __maybe_unused max77838_of_match[] = { 197 { .compatible = "maxim,max77838" }, 198 { /* sentinel */ } 199 }; 200 MODULE_DEVICE_TABLE(of, max77838_of_match); 201 202 static const struct i2c_device_id max77838_id[] = { 203 { "max77838-regulator" }, 204 { /* sentinel */ } 205 }; 206 MODULE_DEVICE_TABLE(i2c, max77838_id); 207 208 static 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 }; 217 module_i2c_driver(max77838_regulator_driver); 218 219 MODULE_AUTHOR("Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>"); 220 MODULE_DESCRIPTION("MAX77838 PMIC regulator driver"); 221 MODULE_LICENSE("GPL"); 222