| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // |
| 3 | // Copyright (c) 2022 MediaTek Inc. |
| 4 | // Copyright (c) 2022 BayLibre, SAS. |
| 5 | // Author: Chen Zhong <chen.zhong@mediatek.com> |
| 6 | // Author: Fabien Parent <fparent@baylibre.com> |
| 7 | // Author: Alexandre Mergnat <amergnat@baylibre.com> |
| 8 | // |
| 9 | // Based on mt6397-regulator.c |
| 10 | // |
| 11 | |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/of.h> |
| 14 | #include <linux/platform_device.h> |
| 15 | #include <linux/regmap.h> |
| 16 | #include <linux/mfd/mt6397/core.h> |
| 17 | #include <linux/mfd/mt6357/registers.h> |
| 18 | #include <linux/regulator/driver.h> |
| 19 | #include <linux/regulator/machine.h> |
| 20 | #include <linux/regulator/mt6357-regulator.h> |
| 21 | #include <linux/regulator/of_regulator.h> |
| 22 | |
| 23 | /* |
| 24 | * MT6357 regulators' information |
| 25 | * |
| 26 | * @desc: standard fields of regulator description. |
| 27 | * @da_vsel_reg: Monitor register for query buck's voltage. |
| 28 | * @da_vsel_mask: Mask for query buck's voltage. |
| 29 | */ |
| 30 | struct mt6357_regulator_info { |
| 31 | struct regulator_desc desc; |
| 32 | u32 da_vsel_reg; |
| 33 | u32 da_vsel_mask; |
| 34 | }; |
| 35 | |
| 36 | #define MT6357_BUCK(match, vreg, min, max, step, \ |
| 37 | volt_ranges, vosel_reg, vosel_mask, _da_vsel_mask) \ |
| 38 | [MT6357_ID_##vreg] = { \ |
| 39 | .desc = { \ |
| 40 | .name = #vreg, \ |
| 41 | .of_match = of_match_ptr(match), \ |
| 42 | .regulators_node = "regulators", \ |
| 43 | .ops = &mt6357_volt_range_ops, \ |
| 44 | .type = REGULATOR_VOLTAGE, \ |
| 45 | .id = MT6357_ID_##vreg, \ |
| 46 | .owner = THIS_MODULE, \ |
| 47 | .n_voltages = ((max) - (min)) / (step) + 1, \ |
| 48 | .linear_ranges = volt_ranges, \ |
| 49 | .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ |
| 50 | .vsel_reg = vosel_reg, \ |
| 51 | .vsel_mask = vosel_mask, \ |
| 52 | .enable_reg = MT6357_BUCK_##vreg##_CON0, \ |
| 53 | .enable_mask = BIT(0), \ |
| 54 | }, \ |
| 55 | .da_vsel_reg = MT6357_BUCK_##vreg##_DBG0, \ |
| 56 | .da_vsel_mask = vosel_mask, \ |
| 57 | } |
| 58 | |
| 59 | #define MT6357_LDO(match, vreg, ldo_volt_table, \ |
| 60 | enreg, vosel, vosel_mask) \ |
| 61 | [MT6357_ID_##vreg] = { \ |
| 62 | .desc = { \ |
| 63 | .name = #vreg, \ |
| 64 | .of_match = of_match_ptr(match), \ |
| 65 | .regulators_node = "regulators", \ |
| 66 | .ops = &mt6357_volt_table_ops, \ |
| 67 | .type = REGULATOR_VOLTAGE, \ |
| 68 | .id = MT6357_ID_##vreg, \ |
| 69 | .owner = THIS_MODULE, \ |
| 70 | .n_voltages = ARRAY_SIZE(ldo_volt_table), \ |
| 71 | .volt_table = ldo_volt_table, \ |
| 72 | .vsel_reg = vosel, \ |
| 73 | .vsel_mask = vosel_mask, \ |
| 74 | .enable_reg = enreg, \ |
| 75 | .enable_mask = BIT(0), \ |
| 76 | }, \ |
| 77 | } |
| 78 | |
| 79 | #define MT6357_LDO1(match, vreg, min, max, step, volt_ranges, \ |
| 80 | enreg, vosel, vosel_mask) \ |
| 81 | [MT6357_ID_##vreg] = { \ |
| 82 | .desc = { \ |
| 83 | .name = #vreg, \ |
| 84 | .of_match = of_match_ptr(match), \ |
| 85 | .regulators_node = "regulators", \ |
| 86 | .ops = &mt6357_volt_range_ops, \ |
| 87 | .type = REGULATOR_VOLTAGE, \ |
| 88 | .id = MT6357_ID_##vreg, \ |
| 89 | .owner = THIS_MODULE, \ |
| 90 | .n_voltages = ((max) - (min)) / (step) + 1, \ |
| 91 | .linear_ranges = volt_ranges, \ |
| 92 | .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ |
| 93 | .vsel_reg = vosel, \ |
| 94 | .vsel_mask = vosel_mask, \ |
| 95 | .enable_reg = enreg, \ |
| 96 | .enable_mask = BIT(0), \ |
| 97 | }, \ |
| 98 | .da_vsel_reg = MT6357_LDO_##vreg##_DBG0, \ |
| 99 | .da_vsel_mask = 0x7f00, \ |
| 100 | } |
| 101 | |
| 102 | #define MT6357_REG_FIXED(match, vreg, volt) \ |
| 103 | [MT6357_ID_##vreg] = { \ |
| 104 | .desc = { \ |
| 105 | .name = #vreg, \ |
| 106 | .of_match = of_match_ptr(match), \ |
| 107 | .regulators_node = "regulators", \ |
| 108 | .ops = &mt6357_volt_fixed_ops, \ |
| 109 | .type = REGULATOR_VOLTAGE, \ |
| 110 | .id = MT6357_ID_##vreg, \ |
| 111 | .owner = THIS_MODULE, \ |
| 112 | .n_voltages = 1, \ |
| 113 | .enable_reg = MT6357_LDO_##vreg##_CON0, \ |
| 114 | .enable_mask = BIT(0), \ |
| 115 | .min_uV = volt, \ |
| 116 | }, \ |
| 117 | } |
| 118 | |
| 119 | /** |
| 120 | * mt6357_get_buck_voltage_sel - get_voltage_sel for regmap users |
| 121 | * |
| 122 | * @rdev: regulator to operate on |
| 123 | * |
| 124 | * Regulators that use regmap for their register I/O can set the |
| 125 | * da_vsel_reg and da_vsel_mask fields in the info structure and |
| 126 | * then use this as their get_voltage_sel operation. |
| 127 | */ |
| 128 | static int mt6357_get_buck_voltage_sel(struct regulator_dev *rdev) |
| 129 | { |
| 130 | int ret, regval; |
| 131 | struct mt6357_regulator_info *info = rdev_get_drvdata(rdev); |
| 132 | |
| 133 | ret = regmap_read(map: rdev->regmap, reg: info->da_vsel_reg, val: ®val); |
| 134 | if (ret != 0) { |
| 135 | dev_err(&rdev->dev, |
| 136 | "Failed to get mt6357 Buck %s vsel reg: %d\n" , |
| 137 | info->desc.name, ret); |
| 138 | return ret; |
| 139 | } |
| 140 | |
| 141 | regval &= info->da_vsel_mask; |
| 142 | regval >>= ffs(info->da_vsel_mask) - 1; |
| 143 | |
| 144 | return regval; |
| 145 | } |
| 146 | |
| 147 | static const struct regulator_ops mt6357_volt_range_ops = { |
| 148 | .list_voltage = regulator_list_voltage_linear_range, |
| 149 | .map_voltage = regulator_map_voltage_linear_range, |
| 150 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 151 | .get_voltage_sel = mt6357_get_buck_voltage_sel, |
| 152 | .set_voltage_time_sel = regulator_set_voltage_time_sel, |
| 153 | .enable = regulator_enable_regmap, |
| 154 | .disable = regulator_disable_regmap, |
| 155 | .is_enabled = regulator_is_enabled_regmap, |
| 156 | }; |
| 157 | |
| 158 | static const struct regulator_ops mt6357_volt_table_ops = { |
| 159 | .list_voltage = regulator_list_voltage_table, |
| 160 | .map_voltage = regulator_map_voltage_iterate, |
| 161 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 162 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 163 | .set_voltage_time_sel = regulator_set_voltage_time_sel, |
| 164 | .enable = regulator_enable_regmap, |
| 165 | .disable = regulator_disable_regmap, |
| 166 | .is_enabled = regulator_is_enabled_regmap, |
| 167 | }; |
| 168 | |
| 169 | static const struct regulator_ops mt6357_volt_fixed_ops = { |
| 170 | .list_voltage = regulator_list_voltage_linear, |
| 171 | .enable = regulator_enable_regmap, |
| 172 | .disable = regulator_disable_regmap, |
| 173 | .is_enabled = regulator_is_enabled_regmap, |
| 174 | }; |
| 175 | |
| 176 | static const int vxo22_voltages[] = { |
| 177 | 2200000, |
| 178 | 0, |
| 179 | 2400000, |
| 180 | }; |
| 181 | |
| 182 | static const int vefuse_voltages[] = { |
| 183 | 1200000, |
| 184 | 1300000, |
| 185 | 1500000, |
| 186 | 0, |
| 187 | 1800000, |
| 188 | 0, |
| 189 | 0, |
| 190 | 0, |
| 191 | 0, |
| 192 | 2800000, |
| 193 | 2900000, |
| 194 | 3000000, |
| 195 | 0, |
| 196 | 3300000, |
| 197 | }; |
| 198 | |
| 199 | static const int vcn33_voltages[] = { |
| 200 | 0, |
| 201 | 3300000, |
| 202 | 3400000, |
| 203 | 3500000, |
| 204 | }; |
| 205 | |
| 206 | static const int vcama_voltages[] = { |
| 207 | 0, |
| 208 | 0, |
| 209 | 0, |
| 210 | 0, |
| 211 | 0, |
| 212 | 0, |
| 213 | 0, |
| 214 | 2500000, |
| 215 | 0, |
| 216 | 0, |
| 217 | 2800000, |
| 218 | }; |
| 219 | |
| 220 | static const int vcamd_voltages[] = { |
| 221 | 0, |
| 222 | 0, |
| 223 | 0, |
| 224 | 0, |
| 225 | 1000000, |
| 226 | 1100000, |
| 227 | 1200000, |
| 228 | 1300000, |
| 229 | 0, |
| 230 | 1500000, |
| 231 | 0, |
| 232 | 0, |
| 233 | 1800000, |
| 234 | }; |
| 235 | |
| 236 | static const int vldo28_voltages[] = { |
| 237 | 0, |
| 238 | 2800000, |
| 239 | 0, |
| 240 | 3000000, |
| 241 | }; |
| 242 | |
| 243 | static const int vdram_voltages[] = { |
| 244 | 0, |
| 245 | 1100000, |
| 246 | 1200000, |
| 247 | }; |
| 248 | |
| 249 | static const int vsim_voltages[] = { |
| 250 | 0, |
| 251 | 0, |
| 252 | 0, |
| 253 | 1700000, |
| 254 | 1800000, |
| 255 | 0, |
| 256 | 0, |
| 257 | 0, |
| 258 | 2700000, |
| 259 | 0, |
| 260 | 0, |
| 261 | 3000000, |
| 262 | 3100000, |
| 263 | }; |
| 264 | |
| 265 | static const int vibr_voltages[] = { |
| 266 | 1200000, |
| 267 | 1300000, |
| 268 | 1500000, |
| 269 | 0, |
| 270 | 1800000, |
| 271 | 2000000, |
| 272 | 0, |
| 273 | 0, |
| 274 | 0, |
| 275 | 2800000, |
| 276 | 0, |
| 277 | 3000000, |
| 278 | 0, |
| 279 | 3300000, |
| 280 | }; |
| 281 | |
| 282 | static const int vmc_voltages[] = { |
| 283 | 0, |
| 284 | 0, |
| 285 | 0, |
| 286 | 0, |
| 287 | 1800000, |
| 288 | 0, |
| 289 | 0, |
| 290 | 0, |
| 291 | 0, |
| 292 | 0, |
| 293 | 2900000, |
| 294 | 3000000, |
| 295 | 0, |
| 296 | 3300000, |
| 297 | }; |
| 298 | |
| 299 | static const int vmch_voltages[] = { |
| 300 | 0, |
| 301 | 0, |
| 302 | 2900000, |
| 303 | 3000000, |
| 304 | 0, |
| 305 | 3300000, |
| 306 | }; |
| 307 | |
| 308 | static const int vemc_voltages[] = { |
| 309 | 0, |
| 310 | 0, |
| 311 | 2900000, |
| 312 | 3000000, |
| 313 | 0, |
| 314 | 3300000, |
| 315 | }; |
| 316 | |
| 317 | static const int vusb_voltages[] = { |
| 318 | 0, |
| 319 | 0, |
| 320 | 0, |
| 321 | 3000000, |
| 322 | 3100000, |
| 323 | }; |
| 324 | |
| 325 | static const struct linear_range buck_volt_range1[] = { |
| 326 | REGULATOR_LINEAR_RANGE(518750, 0, 0x7f, 6250), |
| 327 | }; |
| 328 | |
| 329 | static const struct linear_range buck_volt_range2[] = { |
| 330 | REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250), |
| 331 | }; |
| 332 | |
| 333 | static const struct linear_range buck_volt_range3[] = { |
| 334 | REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000), |
| 335 | }; |
| 336 | |
| 337 | static const struct linear_range buck_volt_range4[] = { |
| 338 | REGULATOR_LINEAR_RANGE(1200000, 0, 0x7f, 12500), |
| 339 | }; |
| 340 | |
| 341 | /* The array is indexed by id(MT6357_ID_XXX) */ |
| 342 | static struct mt6357_regulator_info mt6357_regulators[] = { |
| 343 | /* Bucks */ |
| 344 | MT6357_BUCK("buck-vcore" , VCORE, 518750, 1312500, 6250, |
| 345 | buck_volt_range1, MT6357_BUCK_VCORE_ELR0, 0x7f, 0x7f), |
| 346 | MT6357_BUCK("buck-vproc" , VPROC, 518750, 1312500, 6250, |
| 347 | buck_volt_range1, MT6357_BUCK_VPROC_ELR0, 0x7f, 0x7f), |
| 348 | MT6357_BUCK("buck-vmodem" , VMODEM, 500000, 1293750, 6250, |
| 349 | buck_volt_range2, MT6357_BUCK_VMODEM_ELR0, 0x7f, 0x7f), |
| 350 | MT6357_BUCK("buck-vpa" , VPA, 500000, 3650000, 50000, |
| 351 | buck_volt_range3, MT6357_BUCK_VPA_CON1, 0x3f, 0x3f), |
| 352 | MT6357_BUCK("buck-vs1" , VS1, 1200000, 2787500, 12500, |
| 353 | buck_volt_range4, MT6357_BUCK_VS1_ELR0, 0x7f, 0x7f), |
| 354 | |
| 355 | /* LDOs */ |
| 356 | MT6357_LDO("ldo-vcama" , VCAMA, vcama_voltages, |
| 357 | MT6357_LDO_VCAMA_CON0, MT6357_VCAMA_ANA_CON0, 0xf00), |
| 358 | MT6357_LDO("ldo-vcamd" , VCAMD, vcamd_voltages, |
| 359 | MT6357_LDO_VCAMD_CON0, MT6357_VCAMD_ANA_CON0, 0xf00), |
| 360 | MT6357_LDO("ldo-vcn33-bt" , VCN33_BT, vcn33_voltages, |
| 361 | MT6357_LDO_VCN33_CON0_0, MT6357_VCN33_ANA_CON0, 0x300), |
| 362 | MT6357_LDO("ldo-vcn33-wifi" , VCN33_WIFI, vcn33_voltages, |
| 363 | MT6357_LDO_VCN33_CON0_1, MT6357_VCN33_ANA_CON0, 0x300), |
| 364 | MT6357_LDO("ldo-vdram" , VDRAM, vdram_voltages, |
| 365 | MT6357_LDO_VDRAM_CON0, MT6357_VDRAM_ELR_2, 0x300), |
| 366 | MT6357_LDO("ldo-vefuse" , VEFUSE, vefuse_voltages, |
| 367 | MT6357_LDO_VEFUSE_CON0, MT6357_VEFUSE_ANA_CON0, 0xf00), |
| 368 | MT6357_LDO("ldo-vemc" , VEMC, vemc_voltages, |
| 369 | MT6357_LDO_VEMC_CON0, MT6357_VEMC_ANA_CON0, 0x700), |
| 370 | MT6357_LDO("ldo-vibr" , VIBR, vibr_voltages, |
| 371 | MT6357_LDO_VIBR_CON0, MT6357_VIBR_ANA_CON0, 0xf00), |
| 372 | MT6357_LDO("ldo-vldo28" , VLDO28, vldo28_voltages, |
| 373 | MT6357_LDO_VLDO28_CON0_0, MT6357_VLDO28_ANA_CON0, 0x300), |
| 374 | MT6357_LDO("ldo-vmc" , VMC, vmc_voltages, |
| 375 | MT6357_LDO_VMC_CON0, MT6357_VMC_ANA_CON0, 0xf00), |
| 376 | MT6357_LDO("ldo-vmch" , VMCH, vmch_voltages, |
| 377 | MT6357_LDO_VMCH_CON0, MT6357_VMCH_ANA_CON0, 0x700), |
| 378 | MT6357_LDO("ldo-vsim1" , VSIM1, vsim_voltages, |
| 379 | MT6357_LDO_VSIM1_CON0, MT6357_VSIM1_ANA_CON0, 0xf00), |
| 380 | MT6357_LDO("ldo-vsim2" , VSIM2, vsim_voltages, |
| 381 | MT6357_LDO_VSIM2_CON0, MT6357_VSIM2_ANA_CON0, 0xf00), |
| 382 | MT6357_LDO("ldo-vusb33" , VUSB33, vusb_voltages, |
| 383 | MT6357_LDO_VUSB33_CON0_0, MT6357_VUSB33_ANA_CON0, 0x700), |
| 384 | MT6357_LDO("ldo-vxo22" , VXO22, vxo22_voltages, |
| 385 | MT6357_LDO_VXO22_CON0, MT6357_VXO22_ANA_CON0, 0x300), |
| 386 | |
| 387 | MT6357_LDO1("ldo-vsram-proc" , VSRAM_PROC, 518750, 1312500, 6250, |
| 388 | buck_volt_range1, MT6357_LDO_VSRAM_PROC_CON0, |
| 389 | MT6357_LDO_VSRAM_CON0, 0x7f00), |
| 390 | MT6357_LDO1("ldo-vsram-others" , VSRAM_OTHERS, 518750, 1312500, 6250, |
| 391 | buck_volt_range1, MT6357_LDO_VSRAM_OTHERS_CON0, |
| 392 | MT6357_LDO_VSRAM_CON1, 0x7f00), |
| 393 | |
| 394 | MT6357_REG_FIXED("ldo-vaud28" , VAUD28, 2800000), |
| 395 | MT6357_REG_FIXED("ldo-vaux18" , VAUX18, 1800000), |
| 396 | MT6357_REG_FIXED("ldo-vcamio18" , VCAMIO, 1800000), |
| 397 | MT6357_REG_FIXED("ldo-vcn18" , VCN18, 1800000), |
| 398 | MT6357_REG_FIXED("ldo-vcn28" , VCN28, 2800000), |
| 399 | MT6357_REG_FIXED("ldo-vfe28" , VFE28, 2800000), |
| 400 | MT6357_REG_FIXED("ldo-vio18" , VIO18, 1800000), |
| 401 | MT6357_REG_FIXED("ldo-vio28" , VIO28, 2800000), |
| 402 | MT6357_REG_FIXED("ldo-vrf12" , VRF12, 1200000), |
| 403 | MT6357_REG_FIXED("ldo-vrf18" , VRF18, 1800000), |
| 404 | }; |
| 405 | |
| 406 | static int mt6357_regulator_probe(struct platform_device *pdev) |
| 407 | { |
| 408 | struct mt6397_chip *mt6357 = dev_get_drvdata(dev: pdev->dev.parent); |
| 409 | struct regulator_config config = {}; |
| 410 | struct regulator_dev *rdev; |
| 411 | int i; |
| 412 | |
| 413 | pdev->dev.of_node = pdev->dev.parent->of_node; |
| 414 | |
| 415 | for (i = 0; i < MT6357_MAX_REGULATOR; i++) { |
| 416 | config.dev = &pdev->dev; |
| 417 | config.driver_data = &mt6357_regulators[i]; |
| 418 | config.regmap = mt6357->regmap; |
| 419 | |
| 420 | rdev = devm_regulator_register(dev: &pdev->dev, |
| 421 | regulator_desc: &mt6357_regulators[i].desc, |
| 422 | config: &config); |
| 423 | if (IS_ERR(ptr: rdev)) { |
| 424 | dev_err(&pdev->dev, "failed to register %s\n" , |
| 425 | mt6357_regulators[i].desc.name); |
| 426 | return PTR_ERR(ptr: rdev); |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | return 0; |
| 431 | } |
| 432 | |
| 433 | static const struct platform_device_id mt6357_platform_ids[] = { |
| 434 | { "mt6357-regulator" }, |
| 435 | { /* sentinel */ }, |
| 436 | }; |
| 437 | MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); |
| 438 | |
| 439 | static struct platform_driver mt6357_regulator_driver = { |
| 440 | .driver = { |
| 441 | .name = "mt6357-regulator" , |
| 442 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
| 443 | }, |
| 444 | .probe = mt6357_regulator_probe, |
| 445 | .id_table = mt6357_platform_ids, |
| 446 | }; |
| 447 | |
| 448 | module_platform_driver(mt6357_regulator_driver); |
| 449 | |
| 450 | MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>" ); |
| 451 | MODULE_AUTHOR("Fabien Parent <fabien.parent@linaro.org>" ); |
| 452 | MODULE_AUTHOR("Alexandre Mergnat <amergnat@baylibre.com>" ); |
| 453 | MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6357 PMIC" ); |
| 454 | MODULE_LICENSE("GPL" ); |
| 455 | |