0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/err.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mfd/ti-lmu.h>
0013 #include <linux/mfd/ti-lmu-register.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/gpio/consumer.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/regulator/driver.h>
0019 #include <linux/regulator/of_regulator.h>
0020 #include <linux/slab.h>
0021
0022
0023 #define LM3631_BOOST_VSEL_MAX 0x25
0024 #define LM3631_LDO_VSEL_MAX 0x28
0025 #define LM3631_CONT_VSEL_MAX 0x03
0026 #define LM3631_VBOOST_MIN 4500000
0027 #define LM3631_VCONT_MIN 1800000
0028 #define LM3631_VLDO_MIN 4000000
0029 #define ENABLE_TIME_USEC 1000
0030
0031
0032 #define LM3632_BOOST_VSEL_MAX 0x26
0033 #define LM3632_LDO_VSEL_MAX 0x28
0034 #define LM3632_VBOOST_MIN 4500000
0035 #define LM3632_VLDO_MIN 4000000
0036
0037
0038 #define LM36274_BOOST_VSEL_MAX 0x3f
0039 #define LM36274_LDO_VSEL_MAX 0x32
0040 #define LM36274_VOLTAGE_MIN 4000000
0041
0042
0043 #define LM363X_STEP_50mV 50000
0044 #define LM363X_STEP_500mV 500000
0045
0046 static const int ldo_cont_enable_time[] = {
0047 0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
0048 };
0049
0050 static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
0051 {
0052 enum lm363x_regulator_id id = rdev_get_id(rdev);
0053 unsigned int val, addr, mask;
0054
0055 switch (id) {
0056 case LM3631_LDO_CONT:
0057 addr = LM3631_REG_ENTIME_VCONT;
0058 mask = LM3631_ENTIME_CONT_MASK;
0059 break;
0060 case LM3631_LDO_OREF:
0061 addr = LM3631_REG_ENTIME_VOREF;
0062 mask = LM3631_ENTIME_MASK;
0063 break;
0064 case LM3631_LDO_POS:
0065 addr = LM3631_REG_ENTIME_VPOS;
0066 mask = LM3631_ENTIME_MASK;
0067 break;
0068 case LM3631_LDO_NEG:
0069 addr = LM3631_REG_ENTIME_VNEG;
0070 mask = LM3631_ENTIME_MASK;
0071 break;
0072 default:
0073 return 0;
0074 }
0075
0076 if (regmap_read(rdev->regmap, addr, &val))
0077 return -EINVAL;
0078
0079 val = (val & mask) >> LM3631_ENTIME_SHIFT;
0080
0081 if (id == LM3631_LDO_CONT)
0082 return ldo_cont_enable_time[val];
0083 else
0084 return ENABLE_TIME_USEC * val;
0085 }
0086
0087 static const struct regulator_ops lm363x_boost_voltage_table_ops = {
0088 .list_voltage = regulator_list_voltage_linear,
0089 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0090 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0091 };
0092
0093 static const struct regulator_ops lm363x_regulator_voltage_table_ops = {
0094 .list_voltage = regulator_list_voltage_linear,
0095 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0096 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0097 .enable = regulator_enable_regmap,
0098 .disable = regulator_disable_regmap,
0099 .is_enabled = regulator_is_enabled_regmap,
0100 .enable_time = lm363x_regulator_enable_time,
0101 };
0102
0103 static const struct regulator_desc lm363x_regulator_desc[] = {
0104
0105 {
0106 .name = "vboost",
0107 .of_match = "vboost",
0108 .id = LM3631_BOOST,
0109 .ops = &lm363x_boost_voltage_table_ops,
0110 .n_voltages = LM3631_BOOST_VSEL_MAX + 1,
0111 .min_uV = LM3631_VBOOST_MIN,
0112 .uV_step = LM363X_STEP_50mV,
0113 .type = REGULATOR_VOLTAGE,
0114 .owner = THIS_MODULE,
0115 .vsel_reg = LM3631_REG_VOUT_BOOST,
0116 .vsel_mask = LM3631_VOUT_MASK,
0117 },
0118 {
0119 .name = "ldo_cont",
0120 .of_match = "vcont",
0121 .id = LM3631_LDO_CONT,
0122 .ops = &lm363x_regulator_voltage_table_ops,
0123 .n_voltages = LM3631_CONT_VSEL_MAX + 1,
0124 .min_uV = LM3631_VCONT_MIN,
0125 .uV_step = LM363X_STEP_500mV,
0126 .type = REGULATOR_VOLTAGE,
0127 .owner = THIS_MODULE,
0128 .vsel_reg = LM3631_REG_VOUT_CONT,
0129 .vsel_mask = LM3631_VOUT_CONT_MASK,
0130 .enable_reg = LM3631_REG_LDO_CTRL2,
0131 .enable_mask = LM3631_EN_CONT_MASK,
0132 },
0133 {
0134 .name = "ldo_oref",
0135 .of_match = "voref",
0136 .id = LM3631_LDO_OREF,
0137 .ops = &lm363x_regulator_voltage_table_ops,
0138 .n_voltages = LM3631_LDO_VSEL_MAX + 1,
0139 .min_uV = LM3631_VLDO_MIN,
0140 .uV_step = LM363X_STEP_50mV,
0141 .type = REGULATOR_VOLTAGE,
0142 .owner = THIS_MODULE,
0143 .vsel_reg = LM3631_REG_VOUT_OREF,
0144 .vsel_mask = LM3631_VOUT_MASK,
0145 .enable_reg = LM3631_REG_LDO_CTRL1,
0146 .enable_mask = LM3631_EN_OREF_MASK,
0147 },
0148 {
0149 .name = "ldo_vpos",
0150 .of_match = "vpos",
0151 .id = LM3631_LDO_POS,
0152 .ops = &lm363x_regulator_voltage_table_ops,
0153 .n_voltages = LM3631_LDO_VSEL_MAX + 1,
0154 .min_uV = LM3631_VLDO_MIN,
0155 .uV_step = LM363X_STEP_50mV,
0156 .type = REGULATOR_VOLTAGE,
0157 .owner = THIS_MODULE,
0158 .vsel_reg = LM3631_REG_VOUT_POS,
0159 .vsel_mask = LM3631_VOUT_MASK,
0160 .enable_reg = LM3631_REG_LDO_CTRL1,
0161 .enable_mask = LM3631_EN_VPOS_MASK,
0162 },
0163 {
0164 .name = "ldo_vneg",
0165 .of_match = "vneg",
0166 .id = LM3631_LDO_NEG,
0167 .ops = &lm363x_regulator_voltage_table_ops,
0168 .n_voltages = LM3631_LDO_VSEL_MAX + 1,
0169 .min_uV = LM3631_VLDO_MIN,
0170 .uV_step = LM363X_STEP_50mV,
0171 .type = REGULATOR_VOLTAGE,
0172 .owner = THIS_MODULE,
0173 .vsel_reg = LM3631_REG_VOUT_NEG,
0174 .vsel_mask = LM3631_VOUT_MASK,
0175 .enable_reg = LM3631_REG_LDO_CTRL1,
0176 .enable_mask = LM3631_EN_VNEG_MASK,
0177 },
0178
0179 {
0180 .name = "vboost",
0181 .of_match = "vboost",
0182 .id = LM3632_BOOST,
0183 .ops = &lm363x_boost_voltage_table_ops,
0184 .n_voltages = LM3632_BOOST_VSEL_MAX + 1,
0185 .min_uV = LM3632_VBOOST_MIN,
0186 .uV_step = LM363X_STEP_50mV,
0187 .type = REGULATOR_VOLTAGE,
0188 .owner = THIS_MODULE,
0189 .vsel_reg = LM3632_REG_VOUT_BOOST,
0190 .vsel_mask = LM3632_VOUT_MASK,
0191 },
0192 {
0193 .name = "ldo_vpos",
0194 .of_match = "vpos",
0195 .id = LM3632_LDO_POS,
0196 .ops = &lm363x_regulator_voltage_table_ops,
0197 .n_voltages = LM3632_LDO_VSEL_MAX + 1,
0198 .min_uV = LM3632_VLDO_MIN,
0199 .uV_step = LM363X_STEP_50mV,
0200 .type = REGULATOR_VOLTAGE,
0201 .owner = THIS_MODULE,
0202 .vsel_reg = LM3632_REG_VOUT_POS,
0203 .vsel_mask = LM3632_VOUT_MASK,
0204 .enable_reg = LM3632_REG_BIAS_CONFIG,
0205 .enable_mask = LM3632_EN_VPOS_MASK,
0206 },
0207 {
0208 .name = "ldo_vneg",
0209 .of_match = "vneg",
0210 .id = LM3632_LDO_NEG,
0211 .ops = &lm363x_regulator_voltage_table_ops,
0212 .n_voltages = LM3632_LDO_VSEL_MAX + 1,
0213 .min_uV = LM3632_VLDO_MIN,
0214 .uV_step = LM363X_STEP_50mV,
0215 .type = REGULATOR_VOLTAGE,
0216 .owner = THIS_MODULE,
0217 .vsel_reg = LM3632_REG_VOUT_NEG,
0218 .vsel_mask = LM3632_VOUT_MASK,
0219 .enable_reg = LM3632_REG_BIAS_CONFIG,
0220 .enable_mask = LM3632_EN_VNEG_MASK,
0221 },
0222
0223
0224 {
0225 .name = "vboost",
0226 .of_match = "vboost",
0227 .id = LM36274_BOOST,
0228 .ops = &lm363x_boost_voltage_table_ops,
0229 .n_voltages = LM36274_BOOST_VSEL_MAX + 1,
0230 .min_uV = LM36274_VOLTAGE_MIN,
0231 .uV_step = LM363X_STEP_50mV,
0232 .type = REGULATOR_VOLTAGE,
0233 .owner = THIS_MODULE,
0234 .vsel_reg = LM36274_REG_VOUT_BOOST,
0235 .vsel_mask = LM36274_VOUT_MASK,
0236 },
0237 {
0238 .name = "ldo_vpos",
0239 .of_match = "vpos",
0240 .id = LM36274_LDO_POS,
0241 .ops = &lm363x_regulator_voltage_table_ops,
0242 .n_voltages = LM36274_LDO_VSEL_MAX + 1,
0243 .min_uV = LM36274_VOLTAGE_MIN,
0244 .uV_step = LM363X_STEP_50mV,
0245 .type = REGULATOR_VOLTAGE,
0246 .owner = THIS_MODULE,
0247 .vsel_reg = LM36274_REG_VOUT_POS,
0248 .vsel_mask = LM36274_VOUT_MASK,
0249 .enable_reg = LM36274_REG_BIAS_CONFIG_1,
0250 .enable_mask = LM36274_EN_VPOS_MASK,
0251 },
0252 {
0253 .name = "ldo_vneg",
0254 .of_match = "vneg",
0255 .id = LM36274_LDO_NEG,
0256 .ops = &lm363x_regulator_voltage_table_ops,
0257 .n_voltages = LM36274_LDO_VSEL_MAX + 1,
0258 .min_uV = LM36274_VOLTAGE_MIN,
0259 .uV_step = LM363X_STEP_50mV,
0260 .type = REGULATOR_VOLTAGE,
0261 .owner = THIS_MODULE,
0262 .vsel_reg = LM36274_REG_VOUT_NEG,
0263 .vsel_mask = LM36274_VOUT_MASK,
0264 .enable_reg = LM36274_REG_BIAS_CONFIG_1,
0265 .enable_mask = LM36274_EN_VNEG_MASK,
0266 },
0267 };
0268
0269 static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)
0270 {
0271
0272
0273
0274
0275
0276
0277 switch (id) {
0278 case LM3632_LDO_POS:
0279 case LM36274_LDO_POS:
0280 return gpiod_get_index_optional(dev, "enable", 0,
0281 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
0282 case LM3632_LDO_NEG:
0283 case LM36274_LDO_NEG:
0284 return gpiod_get_index_optional(dev, "enable", 1,
0285 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
0286 default:
0287 return NULL;
0288 }
0289 }
0290
0291 static int lm363x_regulator_set_ext_en(struct regmap *regmap, int id)
0292 {
0293 int ext_en_mask = 0;
0294
0295 switch (id) {
0296 case LM3632_LDO_POS:
0297 case LM3632_LDO_NEG:
0298 ext_en_mask = LM3632_EXT_EN_MASK;
0299 break;
0300 case LM36274_LDO_POS:
0301 case LM36274_LDO_NEG:
0302 ext_en_mask = LM36274_EXT_EN_MASK;
0303 break;
0304 default:
0305 return -ENODEV;
0306 }
0307
0308 return regmap_update_bits(regmap, lm363x_regulator_desc[id].enable_reg,
0309 ext_en_mask, ext_en_mask);
0310 }
0311
0312 static int lm363x_regulator_probe(struct platform_device *pdev)
0313 {
0314 struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
0315 struct regmap *regmap = lmu->regmap;
0316 struct regulator_config cfg = { };
0317 struct regulator_dev *rdev;
0318 struct device *dev = &pdev->dev;
0319 int id = pdev->id;
0320 struct gpio_desc *gpiod;
0321 int ret;
0322
0323 cfg.dev = dev;
0324 cfg.regmap = regmap;
0325
0326
0327
0328
0329
0330 gpiod = lm363x_regulator_of_get_enable_gpio(dev, id);
0331 if (IS_ERR(gpiod))
0332 return PTR_ERR(gpiod);
0333
0334 if (gpiod) {
0335 cfg.ena_gpiod = gpiod;
0336 ret = lm363x_regulator_set_ext_en(regmap, id);
0337 if (ret) {
0338 gpiod_put(gpiod);
0339 dev_err(dev, "External pin err: %d\n", ret);
0340 return ret;
0341 }
0342 }
0343
0344 rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg);
0345 if (IS_ERR(rdev)) {
0346 ret = PTR_ERR(rdev);
0347 dev_err(dev, "[%d] regulator register err: %d\n", id, ret);
0348 return ret;
0349 }
0350
0351 return 0;
0352 }
0353
0354 static struct platform_driver lm363x_regulator_driver = {
0355 .probe = lm363x_regulator_probe,
0356 .driver = {
0357 .name = "lm363x-regulator",
0358 },
0359 };
0360
0361 module_platform_driver(lm363x_regulator_driver);
0362
0363 MODULE_DESCRIPTION("TI LM363X Regulator Driver");
0364 MODULE_AUTHOR("Milo Kim");
0365 MODULE_LICENSE("GPL v2");
0366 MODULE_ALIAS("platform:lm363x-regulator");