1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2017, 2019-2020, The Linux Foundation. All rights reserved. 3 // Copyright (c) 2023, Linaro Limited 4 5 #include <linux/bitfield.h> 6 #include <linux/module.h> 7 #include <linux/of.h> 8 #include <linux/platform_device.h> 9 #include <linux/regmap.h> 10 #include <linux/regulator/driver.h> 11 #include <linux/regulator/machine.h> 12 #include <linux/regulator/of_regulator.h> 13 14 #define REFGEN_REG_BIAS_EN 0x08 15 #define REFGEN_BIAS_EN_MASK GENMASK(2, 0) 16 #define REFGEN_BIAS_EN_ENABLE 0x7 17 #define REFGEN_BIAS_EN_DISABLE 0x6 18 19 #define REFGEN_REG_BG_CTRL 0x14 20 #define REFGEN_BG_CTRL_MASK GENMASK(2, 1) 21 #define REFGEN_BG_CTRL_ENABLE 0x3 22 #define REFGEN_BG_CTRL_DISABLE 0x2 23 24 #define REFGEN_REG_PWRDWN_CTRL5 0x80 25 #define REFGEN_PWRDWN_CTRL5_MASK BIT(0) 26 #define REFGEN_PWRDWN_CTRL5_ENABLE 0x1 27 28 static int qcom_sdm845_refgen_enable(struct regulator_dev *rdev) 29 { 30 regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK, 31 FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_ENABLE)); 32 33 regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN, 34 FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_ENABLE)); 35 36 return 0; 37 } 38 39 static int qcom_sdm845_refgen_disable(struct regulator_dev *rdev) 40 { 41 regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN, 42 FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_DISABLE)); 43 44 regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK, 45 FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_DISABLE)); 46 47 return 0; 48 } 49 50 static int qcom_sdm845_refgen_is_enabled(struct regulator_dev *rdev) 51 { 52 u32 val; 53 54 regmap_read(rdev->regmap, REFGEN_REG_BG_CTRL, &val); 55 if (FIELD_GET(REFGEN_BG_CTRL_MASK, val) != REFGEN_BG_CTRL_ENABLE) 56 return 0; 57 58 regmap_read(rdev->regmap, REFGEN_REG_BIAS_EN, &val); 59 if (FIELD_GET(REFGEN_BIAS_EN_MASK, val) != REFGEN_BIAS_EN_ENABLE) 60 return 0; 61 62 return 1; 63 } 64 65 static struct regulator_desc sdm845_refgen_desc = { 66 .enable_time = 5, 67 .name = "refgen", 68 .owner = THIS_MODULE, 69 .type = REGULATOR_VOLTAGE, 70 .ops = &(const struct regulator_ops) { 71 .enable = qcom_sdm845_refgen_enable, 72 .disable = qcom_sdm845_refgen_disable, 73 .is_enabled = qcom_sdm845_refgen_is_enabled, 74 }, 75 }; 76 77 static struct regulator_desc sm8250_refgen_desc = { 78 .enable_reg = REFGEN_REG_PWRDWN_CTRL5, 79 .enable_mask = REFGEN_PWRDWN_CTRL5_MASK, 80 .enable_val = REFGEN_PWRDWN_CTRL5_ENABLE, 81 .disable_val = 0, 82 .enable_time = 5, 83 .name = "refgen", 84 .owner = THIS_MODULE, 85 .type = REGULATOR_VOLTAGE, 86 .ops = &(const struct regulator_ops) { 87 .enable = regulator_enable_regmap, 88 .disable = regulator_disable_regmap, 89 .is_enabled = regulator_is_enabled_regmap, 90 }, 91 }; 92 93 static const struct regmap_config qcom_refgen_regmap_config = { 94 .reg_bits = 32, 95 .reg_stride = 4, 96 .val_bits = 32, 97 .fast_io = true, 98 }; 99 100 static int qcom_refgen_probe(struct platform_device *pdev) 101 { 102 struct regulator_init_data *init_data; 103 struct regulator_config config = {}; 104 const struct regulator_desc *rdesc; 105 struct device *dev = &pdev->dev; 106 struct regulator_dev *rdev; 107 struct regmap *regmap; 108 void __iomem *base; 109 110 rdesc = of_device_get_match_data(dev); 111 if (!rdesc) 112 return -ENODATA; 113 114 base = devm_platform_ioremap_resource(pdev, 0); 115 if (IS_ERR(base)) 116 return PTR_ERR(base); 117 118 regmap = devm_regmap_init_mmio(dev, base, &qcom_refgen_regmap_config); 119 if (IS_ERR(regmap)) 120 return PTR_ERR(regmap); 121 122 init_data = of_get_regulator_init_data(dev, dev->of_node, rdesc); 123 if (!init_data) 124 return -ENOMEM; 125 126 config.dev = dev; 127 config.init_data = init_data; 128 config.of_node = dev->of_node; 129 config.regmap = regmap; 130 131 rdev = devm_regulator_register(dev, rdesc, &config); 132 if (IS_ERR(rdev)) 133 return PTR_ERR(rdev); 134 135 return 0; 136 } 137 138 static const struct of_device_id qcom_refgen_match_table[] = { 139 { .compatible = "qcom,sdm845-refgen-regulator", .data = &sdm845_refgen_desc }, 140 { .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc }, 141 { } 142 }; 143 MODULE_DEVICE_TABLE(of, qcom_refgen_match_table); 144 145 static struct platform_driver qcom_refgen_driver = { 146 .probe = qcom_refgen_probe, 147 .driver = { 148 .name = "qcom-refgen-regulator", 149 .of_match_table = qcom_refgen_match_table, 150 }, 151 }; 152 module_platform_driver(qcom_refgen_driver); 153 154 MODULE_LICENSE("GPL"); 155 MODULE_DESCRIPTION("Qualcomm REFGEN regulator driver"); 156