Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ROHM BD9571MWV-M and BD9574MWF-M regulator driver
0004  *
0005  * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
0006  *
0007  * Based on the TPS65086 driver
0008  *
0009  * NOTE: VD09 is missing
0010  */
0011 
0012 #include <linux/mfd/rohm-generic.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regulator/driver.h>
0017 
0018 #include <linux/mfd/bd9571mwv.h>
0019 
0020 struct bd9571mwv_reg {
0021     struct regmap *regmap;
0022 
0023     /* DDR Backup Power */
0024     u8 bkup_mode_cnt_keepon;    /* from "rohm,ddr-backup-power" */
0025     u8 bkup_mode_cnt_saved;
0026     bool bkup_mode_enabled;
0027 
0028     /* Power switch type */
0029     bool rstbmode_level;
0030     bool rstbmode_pulse;
0031 };
0032 
0033 enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS };
0034 
0035 #define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
0036     {                           \
0037         .name           = _name,        \
0038         .of_match       = of_match_ptr(_of),    \
0039         .regulators_node    = "regulators",     \
0040         .id         = _id,          \
0041         .ops            = &_ops,        \
0042         .n_voltages     = _nv,          \
0043         .type           = REGULATOR_VOLTAGE,    \
0044         .owner          = THIS_MODULE,      \
0045         .vsel_reg       = _vr,          \
0046         .vsel_mask      = _vm,          \
0047         .min_uV         = _min,         \
0048         .uV_step        = _step,        \
0049         .linear_min_sel     = _lmin,        \
0050     }
0051 
0052 static int bd9571mwv_avs_get_moni_state(struct regulator_dev *rdev)
0053 {
0054     unsigned int val;
0055     int ret;
0056 
0057     ret = regmap_read(rdev->regmap, BD9571MWV_AVS_SET_MONI, &val);
0058     if (ret != 0)
0059         return ret;
0060 
0061     return val & BD9571MWV_AVS_SET_MONI_MASK;
0062 }
0063 
0064 static int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev *rdev,
0065                         unsigned int sel)
0066 {
0067     int ret;
0068 
0069     ret = bd9571mwv_avs_get_moni_state(rdev);
0070     if (ret < 0)
0071         return ret;
0072 
0073     return regmap_write_bits(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret),
0074                  rdev->desc->vsel_mask, sel);
0075 }
0076 
0077 static int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev *rdev)
0078 {
0079     unsigned int val;
0080     int ret;
0081 
0082     ret = bd9571mwv_avs_get_moni_state(rdev);
0083     if (ret < 0)
0084         return ret;
0085 
0086     ret = regmap_read(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret), &val);
0087     if (ret != 0)
0088         return ret;
0089 
0090     val &= rdev->desc->vsel_mask;
0091     val >>= ffs(rdev->desc->vsel_mask) - 1;
0092 
0093     return val;
0094 }
0095 
0096 static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev,
0097                         unsigned int sel)
0098 {
0099     return regmap_write_bits(rdev->regmap, BD9571MWV_DVFS_SETVID,
0100                  rdev->desc->vsel_mask, sel);
0101 }
0102 
0103 /* Operations permitted on AVS voltage regulator */
0104 static const struct regulator_ops avs_ops = {
0105     .set_voltage_sel    = bd9571mwv_avs_set_voltage_sel_regmap,
0106     .map_voltage        = regulator_map_voltage_linear,
0107     .get_voltage_sel    = bd9571mwv_avs_get_voltage_sel_regmap,
0108     .list_voltage       = regulator_list_voltage_linear,
0109 };
0110 
0111 /* Operations permitted on voltage regulators */
0112 static const struct regulator_ops reg_ops = {
0113     .set_voltage_sel    = bd9571mwv_reg_set_voltage_sel_regmap,
0114     .map_voltage        = regulator_map_voltage_linear,
0115     .get_voltage_sel    = regulator_get_voltage_sel_regmap,
0116     .list_voltage       = regulator_list_voltage_linear,
0117 };
0118 
0119 /* Operations permitted on voltage monitors */
0120 static const struct regulator_ops vid_ops = {
0121     .map_voltage        = regulator_map_voltage_linear,
0122     .get_voltage_sel    = regulator_get_voltage_sel_regmap,
0123     .list_voltage       = regulator_list_voltage_linear,
0124 };
0125 
0126 static const struct regulator_desc regulators[] = {
0127     BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
0128               0x6f, 600000, 10000, 0x3c),
0129     BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
0130               16, 1625000, 25000, 0),
0131     BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
0132               16, 2150000, 50000, 0),
0133     BD9571MWV_REG("VD33", "vd33", VD33, vid_ops, BD9571MWV_VD33_VID, 0xf,
0134               11, 2800000, 100000, 0),
0135     BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
0136               BD9571MWV_DVFS_MONIVDAC, 0x7f,
0137               0x6f, 600000, 10000, 0x3c),
0138 };
0139 
0140 #ifdef CONFIG_PM_SLEEP
0141 static int bd9571mwv_bkup_mode_read(struct bd9571mwv_reg *bdreg,
0142                     unsigned int *mode)
0143 {
0144     int ret;
0145 
0146     ret = regmap_read(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
0147     if (ret) {
0148         dev_err(regmap_get_device(bdreg->regmap),
0149             "failed to read backup mode (%d)\n", ret);
0150         return ret;
0151     }
0152 
0153     return 0;
0154 }
0155 
0156 static int bd9571mwv_bkup_mode_write(struct bd9571mwv_reg *bdreg,
0157                      unsigned int mode)
0158 {
0159     int ret;
0160 
0161     ret = regmap_write(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
0162     if (ret) {
0163         dev_err(regmap_get_device(bdreg->regmap),
0164             "failed to configure backup mode 0x%x (%d)\n",
0165             mode, ret);
0166         return ret;
0167     }
0168 
0169     return 0;
0170 }
0171 
0172 static ssize_t backup_mode_show(struct device *dev,
0173                 struct device_attribute *attr, char *buf)
0174 {
0175     struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
0176 
0177     return sysfs_emit(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
0178 }
0179 
0180 static ssize_t backup_mode_store(struct device *dev,
0181                  struct device_attribute *attr,
0182                  const char *buf, size_t count)
0183 {
0184     struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
0185     unsigned int mode;
0186     int ret;
0187 
0188     if (!count)
0189         return 0;
0190 
0191     ret = kstrtobool(buf, &bdreg->bkup_mode_enabled);
0192     if (ret)
0193         return ret;
0194 
0195     if (!bdreg->rstbmode_level)
0196         return count;
0197 
0198     /*
0199      * Configure DDR Backup Mode, to change the role of the accessory power
0200      * switch from a power switch to a wake-up switch, or vice versa
0201      */
0202     ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
0203     if (ret)
0204         return ret;
0205 
0206     mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
0207     if (bdreg->bkup_mode_enabled)
0208         mode |= bdreg->bkup_mode_cnt_keepon;
0209 
0210     ret = bd9571mwv_bkup_mode_write(bdreg, mode);
0211     if (ret)
0212         return ret;
0213 
0214     return count;
0215 }
0216 
0217 static DEVICE_ATTR_RW(backup_mode);
0218 
0219 static int bd9571mwv_suspend(struct device *dev)
0220 {
0221     struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
0222     unsigned int mode;
0223     int ret;
0224 
0225     if (!bdreg->bkup_mode_enabled)
0226         return 0;
0227 
0228     /* Save DDR Backup Mode */
0229     ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
0230     if (ret)
0231         return ret;
0232 
0233     bdreg->bkup_mode_cnt_saved = mode;
0234 
0235     if (!bdreg->rstbmode_pulse)
0236         return 0;
0237 
0238     /* Enable DDR Backup Mode */
0239     mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
0240     mode |= bdreg->bkup_mode_cnt_keepon;
0241 
0242     if (mode != bdreg->bkup_mode_cnt_saved)
0243         return bd9571mwv_bkup_mode_write(bdreg, mode);
0244 
0245     return 0;
0246 }
0247 
0248 static int bd9571mwv_resume(struct device *dev)
0249 {
0250     struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
0251 
0252     if (!bdreg->bkup_mode_enabled)
0253         return 0;
0254 
0255     /* Restore DDR Backup Mode */
0256     return bd9571mwv_bkup_mode_write(bdreg, bdreg->bkup_mode_cnt_saved);
0257 }
0258 
0259 static const struct dev_pm_ops bd9571mwv_pm  = {
0260     SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume)
0261 };
0262 
0263 static int bd9571mwv_regulator_remove(struct platform_device *pdev)
0264 {
0265     device_remove_file(&pdev->dev, &dev_attr_backup_mode);
0266     return 0;
0267 }
0268 #define DEV_PM_OPS  &bd9571mwv_pm
0269 #else
0270 #define DEV_PM_OPS  NULL
0271 #define bd9571mwv_regulator_remove  NULL
0272 #endif /* CONFIG_PM_SLEEP */
0273 
0274 static int bd9571mwv_regulator_probe(struct platform_device *pdev)
0275 {
0276     struct regulator_config config = { };
0277     struct bd9571mwv_reg *bdreg;
0278     struct regulator_dev *rdev;
0279     unsigned int val;
0280     int i;
0281     enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
0282 
0283     bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL);
0284     if (!bdreg)
0285         return -ENOMEM;
0286 
0287     bdreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0288 
0289     platform_set_drvdata(pdev, bdreg);
0290 
0291     config.dev = &pdev->dev;
0292     config.dev->of_node = pdev->dev.parent->of_node;
0293     config.driver_data = bdreg;
0294     config.regmap = bdreg->regmap;
0295 
0296     for (i = 0; i < ARRAY_SIZE(regulators); i++) {
0297         /* BD9574MWF supports DVFS only */
0298         if (chip == ROHM_CHIP_TYPE_BD9574 && regulators[i].id != DVFS)
0299             continue;
0300         rdev = devm_regulator_register(&pdev->dev, &regulators[i],
0301                            &config);
0302         if (IS_ERR(rdev)) {
0303             dev_err(&pdev->dev, "failed to register %s regulator\n",
0304                 regulators[i].name);
0305             return PTR_ERR(rdev);
0306         }
0307     }
0308 
0309     val = 0;
0310     of_property_read_u32(config.dev->of_node, "rohm,ddr-backup-power", &val);
0311     if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) {
0312         dev_err(&pdev->dev, "invalid %s mode %u\n",
0313             "rohm,ddr-backup-power", val);
0314         return -EINVAL;
0315     }
0316     bdreg->bkup_mode_cnt_keepon = val;
0317 
0318     bdreg->rstbmode_level = of_property_read_bool(config.dev->of_node,
0319                               "rohm,rstbmode-level");
0320     bdreg->rstbmode_pulse = of_property_read_bool(config.dev->of_node,
0321                               "rohm,rstbmode-pulse");
0322     if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) {
0323         dev_err(&pdev->dev, "only one rohm,rstbmode-* may be specified");
0324         return -EINVAL;
0325     }
0326 
0327 #ifdef CONFIG_PM_SLEEP
0328     if (bdreg->bkup_mode_cnt_keepon) {
0329         int ret;
0330 
0331         /*
0332          * Backup mode is enabled by default in pulse mode, but needs
0333          * explicit user setup in level mode.
0334          */
0335         bdreg->bkup_mode_enabled = bdreg->rstbmode_pulse;
0336 
0337         ret = device_create_file(&pdev->dev, &dev_attr_backup_mode);
0338         if (ret)
0339             return ret;
0340     }
0341 #endif /* CONFIG_PM_SLEEP */
0342 
0343     return 0;
0344 }
0345 
0346 static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
0347     { "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 },
0348     { "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 },
0349     { /* sentinel */ }
0350 };
0351 MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
0352 
0353 static struct platform_driver bd9571mwv_regulator_driver = {
0354     .driver = {
0355         .name = "bd9571mwv-regulator",
0356         .pm = DEV_PM_OPS,
0357     },
0358     .probe = bd9571mwv_regulator_probe,
0359     .remove = bd9571mwv_regulator_remove,
0360     .id_table = bd9571mwv_regulator_id_table,
0361 };
0362 module_platform_driver(bd9571mwv_regulator_driver);
0363 
0364 MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
0365 MODULE_DESCRIPTION("BD9571MWV Regulator driver");
0366 MODULE_LICENSE("GPL v2");