linux/drivers/regulator/bd9571mwv-regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ROHM BD9571MWV-M regulator driver
   4 *
   5 * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
   6 *
   7 * Based on the TPS65086 driver
   8 *
   9 * NOTE: VD09 is missing
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/platform_device.h>
  15#include <linux/regulator/driver.h>
  16
  17#include <linux/mfd/bd9571mwv.h>
  18
  19struct bd9571mwv_reg {
  20        struct bd9571mwv *bd;
  21
  22        /* DDR Backup Power */
  23        u8 bkup_mode_cnt_keepon;        /* from "rohm,ddr-backup-power" */
  24        u8 bkup_mode_cnt_saved;
  25        bool bkup_mode_enabled;
  26
  27        /* Power switch type */
  28        bool rstbmode_level;
  29        bool rstbmode_pulse;
  30};
  31
  32enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS };
  33
  34#define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
  35        {                                                       \
  36                .name                   = _name,                \
  37                .of_match               = of_match_ptr(_of),    \
  38                .regulators_node        = "regulators",         \
  39                .id                     = _id,                  \
  40                .ops                    = &_ops,                \
  41                .n_voltages             = _nv,                  \
  42                .type                   = REGULATOR_VOLTAGE,    \
  43                .owner                  = THIS_MODULE,          \
  44                .vsel_reg               = _vr,                  \
  45                .vsel_mask              = _vm,                  \
  46                .min_uV                 = _min,                 \
  47                .uV_step                = _step,                \
  48                .linear_min_sel         = _lmin,                \
  49        }
  50
  51static int bd9571mwv_avs_get_moni_state(struct regulator_dev *rdev)
  52{
  53        unsigned int val;
  54        int ret;
  55
  56        ret = regmap_read(rdev->regmap, BD9571MWV_AVS_SET_MONI, &val);
  57        if (ret != 0)
  58                return ret;
  59
  60        return val & BD9571MWV_AVS_SET_MONI_MASK;
  61}
  62
  63static int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev *rdev,
  64                                                unsigned int sel)
  65{
  66        int ret;
  67
  68        ret = bd9571mwv_avs_get_moni_state(rdev);
  69        if (ret < 0)
  70                return ret;
  71
  72        return regmap_write_bits(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret),
  73                                 rdev->desc->vsel_mask, sel);
  74}
  75
  76static int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev *rdev)
  77{
  78        unsigned int val;
  79        int ret;
  80
  81        ret = bd9571mwv_avs_get_moni_state(rdev);
  82        if (ret < 0)
  83                return ret;
  84
  85        ret = regmap_read(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret), &val);
  86        if (ret != 0)
  87                return ret;
  88
  89        val &= rdev->desc->vsel_mask;
  90        val >>= ffs(rdev->desc->vsel_mask) - 1;
  91
  92        return val;
  93}
  94
  95static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev,
  96                                                unsigned int sel)
  97{
  98        return regmap_write_bits(rdev->regmap, BD9571MWV_DVFS_SETVID,
  99                                 rdev->desc->vsel_mask, sel);
 100}
 101
 102/* Operations permitted on AVS voltage regulator */
 103static const struct regulator_ops avs_ops = {
 104        .set_voltage_sel        = bd9571mwv_avs_set_voltage_sel_regmap,
 105        .map_voltage            = regulator_map_voltage_linear,
 106        .get_voltage_sel        = bd9571mwv_avs_get_voltage_sel_regmap,
 107        .list_voltage           = regulator_list_voltage_linear,
 108};
 109
 110/* Operations permitted on voltage regulators */
 111static const struct regulator_ops reg_ops = {
 112        .set_voltage_sel        = bd9571mwv_reg_set_voltage_sel_regmap,
 113        .map_voltage            = regulator_map_voltage_linear,
 114        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
 115        .list_voltage           = regulator_list_voltage_linear,
 116};
 117
 118/* Operations permitted on voltage monitors */
 119static const struct regulator_ops vid_ops = {
 120        .map_voltage            = regulator_map_voltage_linear,
 121        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
 122        .list_voltage           = regulator_list_voltage_linear,
 123};
 124
 125static const struct regulator_desc regulators[] = {
 126        BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
 127                      0x80, 600000, 10000, 0x3c),
 128        BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
 129                      16, 1625000, 25000, 0),
 130        BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
 131                      16, 2150000, 50000, 0),
 132        BD9571MWV_REG("VD33", "vd33", VD33, vid_ops, BD9571MWV_VD33_VID, 0xf,
 133                      11, 2800000, 100000, 0),
 134        BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
 135                      BD9571MWV_DVFS_MONIVDAC, 0x7f,
 136                      0x80, 600000, 10000, 0x3c),
 137};
 138
 139#ifdef CONFIG_PM_SLEEP
 140static int bd9571mwv_bkup_mode_read(struct bd9571mwv *bd, unsigned int *mode)
 141{
 142        int ret;
 143
 144        ret = regmap_read(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
 145        if (ret) {
 146                dev_err(bd->dev, "failed to read backup mode (%d)\n", ret);
 147                return ret;
 148        }
 149
 150        return 0;
 151}
 152
 153static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode)
 154{
 155        int ret;
 156
 157        ret = regmap_write(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
 158        if (ret) {
 159                dev_err(bd->dev, "failed to configure backup mode 0x%x (%d)\n",
 160                        mode, ret);
 161                return ret;
 162        }
 163
 164        return 0;
 165}
 166
 167static ssize_t backup_mode_show(struct device *dev,
 168                                struct device_attribute *attr, char *buf)
 169{
 170        struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
 171
 172        return sprintf(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
 173}
 174
 175static ssize_t backup_mode_store(struct device *dev,
 176                                 struct device_attribute *attr,
 177                                 const char *buf, size_t count)
 178{
 179        struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
 180        unsigned int mode;
 181        int ret;
 182
 183        if (!count)
 184                return 0;
 185
 186        ret = kstrtobool(buf, &bdreg->bkup_mode_enabled);
 187        if (ret)
 188                return ret;
 189
 190        if (!bdreg->rstbmode_level)
 191                return count;
 192
 193        /*
 194         * Configure DDR Backup Mode, to change the role of the accessory power
 195         * switch from a power switch to a wake-up switch, or vice versa
 196         */
 197        ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
 198        if (ret)
 199                return ret;
 200
 201        mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
 202        if (bdreg->bkup_mode_enabled)
 203                mode |= bdreg->bkup_mode_cnt_keepon;
 204
 205        ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode);
 206        if (ret)
 207                return ret;
 208
 209        return count;
 210}
 211
 212static DEVICE_ATTR_RW(backup_mode);
 213
 214static int bd9571mwv_suspend(struct device *dev)
 215{
 216        struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
 217        unsigned int mode;
 218        int ret;
 219
 220        if (!bdreg->bkup_mode_enabled)
 221                return 0;
 222
 223        /* Save DDR Backup Mode */
 224        ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
 225        if (ret)
 226                return ret;
 227
 228        bdreg->bkup_mode_cnt_saved = mode;
 229
 230        if (!bdreg->rstbmode_pulse)
 231                return 0;
 232
 233        /* Enable DDR Backup Mode */
 234        mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
 235        mode |= bdreg->bkup_mode_cnt_keepon;
 236
 237        if (mode != bdreg->bkup_mode_cnt_saved)
 238                return bd9571mwv_bkup_mode_write(bdreg->bd, mode);
 239
 240        return 0;
 241}
 242
 243static int bd9571mwv_resume(struct device *dev)
 244{
 245        struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
 246
 247        if (!bdreg->bkup_mode_enabled)
 248                return 0;
 249
 250        /* Restore DDR Backup Mode */
 251        return bd9571mwv_bkup_mode_write(bdreg->bd, bdreg->bkup_mode_cnt_saved);
 252}
 253
 254static const struct dev_pm_ops bd9571mwv_pm  = {
 255        SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume)
 256};
 257
 258static int bd9571mwv_regulator_remove(struct platform_device *pdev)
 259{
 260        device_remove_file(&pdev->dev, &dev_attr_backup_mode);
 261        return 0;
 262}
 263#define DEV_PM_OPS      &bd9571mwv_pm
 264#else
 265#define DEV_PM_OPS      NULL
 266#define bd9571mwv_regulator_remove      NULL
 267#endif /* CONFIG_PM_SLEEP */
 268
 269static int bd9571mwv_regulator_probe(struct platform_device *pdev)
 270{
 271        struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent);
 272        struct regulator_config config = { };
 273        struct bd9571mwv_reg *bdreg;
 274        struct regulator_dev *rdev;
 275        unsigned int val;
 276        int i;
 277
 278        bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL);
 279        if (!bdreg)
 280                return -ENOMEM;
 281
 282        bdreg->bd = bd;
 283
 284        platform_set_drvdata(pdev, bdreg);
 285
 286        config.dev = &pdev->dev;
 287        config.dev->of_node = bd->dev->of_node;
 288        config.driver_data = bd;
 289        config.regmap = bd->regmap;
 290
 291        for (i = 0; i < ARRAY_SIZE(regulators); i++) {
 292                rdev = devm_regulator_register(&pdev->dev, &regulators[i],
 293                                               &config);
 294                if (IS_ERR(rdev)) {
 295                        dev_err(bd->dev, "failed to register %s regulator\n",
 296                                pdev->name);
 297                        return PTR_ERR(rdev);
 298                }
 299        }
 300
 301        val = 0;
 302        of_property_read_u32(bd->dev->of_node, "rohm,ddr-backup-power", &val);
 303        if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) {
 304                dev_err(bd->dev, "invalid %s mode %u\n",
 305                        "rohm,ddr-backup-power", val);
 306                return -EINVAL;
 307        }
 308        bdreg->bkup_mode_cnt_keepon = val;
 309
 310        bdreg->rstbmode_level = of_property_read_bool(bd->dev->of_node,
 311                                                      "rohm,rstbmode-level");
 312        bdreg->rstbmode_pulse = of_property_read_bool(bd->dev->of_node,
 313                                                      "rohm,rstbmode-pulse");
 314        if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) {
 315                dev_err(bd->dev, "only one rohm,rstbmode-* may be specified");
 316                return -EINVAL;
 317        }
 318
 319#ifdef CONFIG_PM_SLEEP
 320        if (bdreg->bkup_mode_cnt_keepon) {
 321                int ret;
 322
 323                /*
 324                 * Backup mode is enabled by default in pulse mode, but needs
 325                 * explicit user setup in level mode.
 326                 */
 327                bdreg->bkup_mode_enabled = bdreg->rstbmode_pulse;
 328
 329                ret = device_create_file(&pdev->dev, &dev_attr_backup_mode);
 330                if (ret)
 331                        return ret;
 332        }
 333#endif /* CONFIG_PM_SLEEP */
 334
 335        return 0;
 336}
 337
 338static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
 339        { "bd9571mwv-regulator", },
 340        { /* sentinel */ }
 341};
 342MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
 343
 344static struct platform_driver bd9571mwv_regulator_driver = {
 345        .driver = {
 346                .name = "bd9571mwv-regulator",
 347                .pm = DEV_PM_OPS,
 348        },
 349        .probe = bd9571mwv_regulator_probe,
 350        .remove = bd9571mwv_regulator_remove,
 351        .id_table = bd9571mwv_regulator_id_table,
 352};
 353module_platform_driver(bd9571mwv_regulator_driver);
 354
 355MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
 356MODULE_DESCRIPTION("BD9571MWV Regulator driver");
 357MODULE_LICENSE("GPL v2");
 358