0001
0002
0003 #include <linux/bits.h>
0004 #include <linux/gpio/consumer.h>
0005 #include <linux/interrupt.h>
0006 #include <linux/kernel.h>
0007 #include <linux/mod_devicetable.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/regmap.h>
0012 #include <linux/regulator/driver.h>
0013 #include <linux/regulator/machine.h>
0014
0015 enum {
0016 MT6370_IDX_DSVBOOST = 0,
0017 MT6370_IDX_DSVPOS,
0018 MT6370_IDX_DSVNEG,
0019 MT6370_IDX_VIBLDO,
0020 MT6370_MAX_IDX
0021 };
0022
0023 #define MT6370_REG_LDO_CFG 0x180
0024 #define MT6370_REG_LDO_VOUT 0x181
0025 #define MT6370_REG_DB_CTRL1 0x1B0
0026 #define MT6370_REG_DB_CTRL2 0x1B1
0027 #define MT6370_REG_DB_VBST 0x1B2
0028 #define MT6370_REG_DB_VPOS 0x1B3
0029 #define MT6370_REG_DB_VNEG 0x1B4
0030 #define MT6370_REG_LDO_STAT 0x1DC
0031 #define MT6370_REG_DB_STAT 0x1DF
0032
0033 #define MT6370_LDOOMS_MASK BIT(7)
0034 #define MT6370_LDOEN_MASK BIT(7)
0035 #define MT6370_LDOVOUT_MASK GENMASK(3, 0)
0036 #define MT6370_DBPERD_MASK (BIT(7) | BIT(4))
0037 #define MT6370_DBEXTEN_MASK BIT(0)
0038 #define MT6370_DBVPOSEN_MASK BIT(6)
0039 #define MT6370_DBVPOSDISG_MASK BIT(5)
0040 #define MT6370_DBVNEGEN_MASK BIT(3)
0041 #define MT6370_DBVNEGDISG_MASK BIT(2)
0042 #define MT6370_DBALLON_MASK (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK)
0043 #define MT6370_DBSLEW_MASK GENMASK(7, 6)
0044 #define MT6370_DBVOUT_MASK GENMASK(5, 0)
0045 #define MT6370_LDOOC_EVT_MASK BIT(7)
0046 #define MT6370_POSSCP_EVT_MASK BIT(7)
0047 #define MT6370_NEGSCP_EVT_MASK BIT(6)
0048 #define MT6370_BSTOCP_EVT_MASK BIT(5)
0049 #define MT6370_POSOCP_EVT_MASK BIT(4)
0050 #define MT6370_NEGOCP_EVT_MASK BIT(3)
0051
0052 #define MT6370_LDO_MINUV 1600000
0053 #define MT6370_LDO_STPUV 200000
0054 #define MT6370_LDO_N_VOLT 13
0055 #define MT6370_DBVBOOST_MINUV 4000000
0056 #define MT6370_DBVBOOST_STPUV 50000
0057 #define MT6370_DBVBOOST_N_VOLT 45
0058 #define MT6370_DBVOUT_MINUV 4000000
0059 #define MT6370_DBVOUT_STPUV 50000
0060 #define MT6370_DBVOUT_N_VOLT 41
0061
0062 struct mt6370_priv {
0063 struct device *dev;
0064 struct regmap *regmap;
0065 struct regulator_dev *rdev[MT6370_MAX_IDX];
0066 bool use_external_ctrl;
0067 };
0068
0069 static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 };
0070 static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 };
0071
0072 static int mt6370_get_error_flags(struct regulator_dev *rdev,
0073 unsigned int *flags)
0074 {
0075 struct regmap *regmap = rdev_get_regmap(rdev);
0076 unsigned int stat_reg, stat, rpt_flags = 0;
0077 int rid = rdev_get_id(rdev), ret;
0078
0079 if (rid == MT6370_IDX_VIBLDO)
0080 stat_reg = MT6370_REG_LDO_STAT;
0081 else
0082 stat_reg = MT6370_REG_DB_STAT;
0083
0084 ret = regmap_read(regmap, stat_reg, &stat);
0085 if (ret)
0086 return ret;
0087
0088 switch (rid) {
0089 case MT6370_IDX_DSVBOOST:
0090 if (stat & MT6370_BSTOCP_EVT_MASK)
0091 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
0092 break;
0093 case MT6370_IDX_DSVPOS:
0094 if (stat & MT6370_POSSCP_EVT_MASK)
0095 rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
0096
0097 if (stat & MT6370_POSOCP_EVT_MASK)
0098 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
0099 break;
0100 case MT6370_IDX_DSVNEG:
0101 if (stat & MT6370_NEGSCP_EVT_MASK)
0102 rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;
0103
0104 if (stat & MT6370_NEGOCP_EVT_MASK)
0105 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
0106 break;
0107 default:
0108 if (stat & MT6370_LDOOC_EVT_MASK)
0109 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;
0110 break;
0111 }
0112
0113 *flags = rpt_flags;
0114 return 0;
0115 }
0116
0117 static const struct regulator_ops mt6370_dbvboost_ops = {
0118 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0119 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0120 .list_voltage = regulator_list_voltage_linear,
0121 .get_bypass = regulator_get_bypass_regmap,
0122 .set_bypass = regulator_set_bypass_regmap,
0123 .get_error_flags = mt6370_get_error_flags,
0124 };
0125
0126 static const struct regulator_ops mt6370_dbvout_ops = {
0127 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0128 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0129 .list_voltage = regulator_list_voltage_linear,
0130 .is_enabled = regulator_is_enabled_regmap,
0131 .enable = regulator_enable_regmap,
0132 .disable = regulator_disable_regmap,
0133 .set_active_discharge = regulator_set_active_discharge_regmap,
0134 .set_ramp_delay = regulator_set_ramp_delay_regmap,
0135 .get_error_flags = mt6370_get_error_flags,
0136 };
0137
0138 static const struct regulator_ops mt6370_ldo_ops = {
0139 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0140 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0141 .list_voltage = regulator_list_voltage_linear,
0142 .is_enabled = regulator_is_enabled_regmap,
0143 .enable = regulator_enable_regmap,
0144 .disable = regulator_disable_regmap,
0145 .set_active_discharge = regulator_set_active_discharge_regmap,
0146 .get_error_flags = mt6370_get_error_flags,
0147 };
0148
0149 static int mt6370_of_parse_cb(struct device_node *np,
0150 const struct regulator_desc *desc,
0151 struct regulator_config *config)
0152 {
0153 struct mt6370_priv *priv = config->driver_data;
0154 struct gpio_desc *enable_gpio;
0155 int ret;
0156
0157 enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0,
0158 GPIOD_OUT_HIGH |
0159 GPIOD_FLAGS_BIT_NONEXCLUSIVE,
0160 desc->name);
0161 if (IS_ERR(enable_gpio)) {
0162 config->ena_gpiod = NULL;
0163 return 0;
0164 }
0165
0166
0167
0168
0169
0170 if (priv->use_external_ctrl) {
0171 ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1,
0172 MT6370_DBEXTEN_MASK,
0173 MT6370_DBEXTEN_MASK);
0174 if (ret)
0175 return ret;
0176 }
0177
0178 config->ena_gpiod = enable_gpio;
0179 priv->use_external_ctrl = true;
0180 return 0;
0181 }
0182
0183 static const struct regulator_desc mt6370_regulator_descs[] = {
0184 {
0185 .name = "mt6370-dsv-vbst",
0186 .of_match = of_match_ptr("dsvbst"),
0187 .regulators_node = of_match_ptr("regulators"),
0188 .id = MT6370_IDX_DSVBOOST,
0189 .type = REGULATOR_VOLTAGE,
0190 .owner = THIS_MODULE,
0191 .ops = &mt6370_dbvboost_ops,
0192 .min_uV = MT6370_DBVBOOST_MINUV,
0193 .uV_step = MT6370_DBVBOOST_STPUV,
0194 .n_voltages = MT6370_DBVBOOST_N_VOLT,
0195 .vsel_reg = MT6370_REG_DB_VBST,
0196 .vsel_mask = MT6370_DBVOUT_MASK,
0197 .bypass_reg = MT6370_REG_DB_CTRL1,
0198 .bypass_mask = MT6370_DBPERD_MASK,
0199 .bypass_val_on = MT6370_DBPERD_MASK,
0200 },
0201 {
0202 .name = "mt6370-dsv-vpos",
0203 .of_match = of_match_ptr("dsvpos"),
0204 .regulators_node = of_match_ptr("regulators"),
0205 .id = MT6370_IDX_DSVPOS,
0206 .type = REGULATOR_VOLTAGE,
0207 .owner = THIS_MODULE,
0208 .of_parse_cb = mt6370_of_parse_cb,
0209 .ops = &mt6370_dbvout_ops,
0210 .min_uV = MT6370_DBVOUT_MINUV,
0211 .uV_step = MT6370_DBVOUT_STPUV,
0212 .n_voltages = MT6370_DBVOUT_N_VOLT,
0213 .vsel_reg = MT6370_REG_DB_VPOS,
0214 .vsel_mask = MT6370_DBVOUT_MASK,
0215 .enable_reg = MT6370_REG_DB_CTRL2,
0216 .enable_mask = MT6370_DBVPOSEN_MASK,
0217 .ramp_reg = MT6370_REG_DB_VPOS,
0218 .ramp_mask = MT6370_DBSLEW_MASK,
0219 .ramp_delay_table = mt6370_vpos_ramp_tbl,
0220 .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl),
0221 .active_discharge_reg = MT6370_REG_DB_CTRL2,
0222 .active_discharge_mask = MT6370_DBVPOSDISG_MASK,
0223 .active_discharge_on = MT6370_DBVPOSDISG_MASK,
0224 },
0225 {
0226 .name = "mt6370-dsv-vneg",
0227 .of_match = of_match_ptr("dsvneg"),
0228 .regulators_node = of_match_ptr("regulators"),
0229 .id = MT6370_IDX_DSVNEG,
0230 .type = REGULATOR_VOLTAGE,
0231 .owner = THIS_MODULE,
0232 .of_parse_cb = mt6370_of_parse_cb,
0233 .ops = &mt6370_dbvout_ops,
0234 .min_uV = MT6370_DBVOUT_MINUV,
0235 .uV_step = MT6370_DBVOUT_STPUV,
0236 .n_voltages = MT6370_DBVOUT_N_VOLT,
0237 .vsel_reg = MT6370_REG_DB_VNEG,
0238 .vsel_mask = MT6370_DBVOUT_MASK,
0239 .enable_reg = MT6370_REG_DB_CTRL2,
0240 .enable_mask = MT6370_DBVNEGEN_MASK,
0241 .ramp_reg = MT6370_REG_DB_VNEG,
0242 .ramp_mask = MT6370_DBSLEW_MASK,
0243 .ramp_delay_table = mt6370_vneg_ramp_tbl,
0244 .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl),
0245 .active_discharge_reg = MT6370_REG_DB_CTRL2,
0246 .active_discharge_mask = MT6370_DBVNEGDISG_MASK,
0247 .active_discharge_on = MT6370_DBVNEGDISG_MASK,
0248 },
0249 {
0250 .name = "mt6370-vib-ldo",
0251 .of_match = of_match_ptr("vibldo"),
0252 .regulators_node = of_match_ptr("regulators"),
0253 .id = MT6370_IDX_VIBLDO,
0254 .type = REGULATOR_VOLTAGE,
0255 .owner = THIS_MODULE,
0256 .ops = &mt6370_ldo_ops,
0257 .min_uV = MT6370_LDO_MINUV,
0258 .uV_step = MT6370_LDO_STPUV,
0259 .n_voltages = MT6370_LDO_N_VOLT,
0260 .vsel_reg = MT6370_REG_LDO_VOUT,
0261 .vsel_mask = MT6370_LDOVOUT_MASK,
0262 .enable_reg = MT6370_REG_LDO_VOUT,
0263 .enable_mask = MT6370_LDOEN_MASK,
0264 .active_discharge_reg = MT6370_REG_LDO_CFG,
0265 .active_discharge_mask = MT6370_LDOOMS_MASK,
0266 .active_discharge_on = MT6370_LDOOMS_MASK,
0267 }
0268 };
0269
0270 static irqreturn_t mt6370_scp_handler(int irq, void *data)
0271 {
0272 struct regulator_dev *rdev = data;
0273
0274 regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE,
0275 NULL);
0276 return IRQ_HANDLED;
0277 }
0278
0279 static irqreturn_t mt6370_ocp_handler(int irq, void *data)
0280 {
0281 struct regulator_dev *rdev = data;
0282
0283 regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
0284 return IRQ_HANDLED;
0285 }
0286
0287 static int mt6370_regulator_irq_register(struct mt6370_priv *priv)
0288 {
0289 struct platform_device *pdev = to_platform_device(priv->dev);
0290 static const struct {
0291 const char *name;
0292 int rid;
0293 irq_handler_t handler;
0294 } mt6370_irqs[] = {
0295 { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler },
0296 { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler },
0297 { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler },
0298 { "db_vpos_ocp", MT6370_IDX_DSVPOS, mt6370_ocp_handler },
0299 { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler },
0300 { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler }
0301 };
0302 struct regulator_dev *rdev;
0303 int i, irq, ret;
0304
0305 for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) {
0306 irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name);
0307
0308 rdev = priv->rdev[mt6370_irqs[i].rid];
0309
0310 ret = devm_request_threaded_irq(priv->dev, irq, NULL,
0311 mt6370_irqs[i].handler, 0,
0312 mt6370_irqs[i].name, rdev);
0313 if (ret) {
0314 dev_err(priv->dev,
0315 "Failed to register (%d) interrupt\n", i);
0316 return ret;
0317 }
0318 }
0319
0320 return 0;
0321 }
0322
0323 static int mt6370_regualtor_register(struct mt6370_priv *priv)
0324 {
0325 struct regulator_dev *rdev;
0326 struct regulator_config cfg = {};
0327 struct device *parent = priv->dev->parent;
0328 int i;
0329
0330 cfg.dev = parent;
0331 cfg.driver_data = priv;
0332
0333 for (i = 0; i < MT6370_MAX_IDX; i++) {
0334 rdev = devm_regulator_register(priv->dev,
0335 mt6370_regulator_descs + i,
0336 &cfg);
0337 if (IS_ERR(rdev)) {
0338 dev_err(priv->dev,
0339 "Failed to register (%d) regulator\n", i);
0340 return PTR_ERR(rdev);
0341 }
0342
0343 priv->rdev[i] = rdev;
0344 }
0345
0346 return 0;
0347 }
0348
0349 static int mt6370_regulator_probe(struct platform_device *pdev)
0350 {
0351 struct mt6370_priv *priv;
0352 int ret;
0353
0354 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0355 if (!priv)
0356 return -ENOMEM;
0357
0358 priv->dev = &pdev->dev;
0359
0360 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0361 if (!priv->regmap) {
0362 dev_err(&pdev->dev, "Failed to init regmap\n");
0363 return -ENODEV;
0364 }
0365
0366 ret = mt6370_regualtor_register(priv);
0367 if (ret)
0368 return ret;
0369
0370 return mt6370_regulator_irq_register(priv);
0371 }
0372
0373 static const struct platform_device_id mt6370_devid_table[] = {
0374 { "mt6370-regulator", 0},
0375 {}
0376 };
0377 MODULE_DEVICE_TABLE(platform, mt6370_devid_table);
0378
0379 static struct platform_driver mt6370_regulator_driver = {
0380 .driver = {
0381 .name = "mt6370-regulator",
0382 },
0383 .id_table = mt6370_devid_table,
0384 .probe = mt6370_regulator_probe,
0385 };
0386 module_platform_driver(mt6370_regulator_driver);
0387
0388 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
0389 MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver");
0390 MODULE_LICENSE("GPL v2");