linux/drivers/regulator/hi6421v530-regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Device driver for regulators in Hi6421V530 IC
   4//
   5// Copyright (c) <2017> HiSilicon Technologies Co., Ltd.
   6//              http://www.hisilicon.com
   7// Copyright (c) <2017> Linaro Ltd.
   8//              https://www.linaro.org
   9//
  10// Author: Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>
  11//         Guodong Xu <guodong.xu@linaro.org>
  12
  13#include <linux/mfd/hi6421-pmic.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/platform_device.h>
  17#include <linux/regmap.h>
  18#include <linux/regulator/driver.h>
  19
  20/*
  21 * struct hi6421v530_regulator_info - hi6421v530 regulator information
  22 * @desc: regulator description
  23 * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
  24 * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
  25 */
  26struct hi6421v530_regulator_info {
  27        struct regulator_desc rdesc;
  28        u8 mode_mask;
  29        u32 eco_microamp;
  30};
  31
  32/* HI6421v530 regulators */
  33enum hi6421v530_regulator_id {
  34        HI6421V530_LDO3,
  35        HI6421V530_LDO9,
  36        HI6421V530_LDO11,
  37        HI6421V530_LDO15,
  38        HI6421V530_LDO16,
  39};
  40
  41static const unsigned int ldo_3_voltages[] = {
  42        1800000, 1825000, 1850000, 1875000,
  43        1900000, 1925000, 1950000, 1975000,
  44        2000000, 2025000, 2050000, 2075000,
  45        2100000, 2125000, 2150000, 2200000,
  46};
  47
  48static const unsigned int ldo_9_11_voltages[] = {
  49        1750000, 1800000, 1825000, 2800000,
  50        2850000, 2950000, 3000000, 3300000,
  51};
  52
  53static const unsigned int ldo_15_16_voltages[] = {
  54        1750000, 1800000, 2400000, 2600000,
  55        2700000, 2850000, 2950000, 3000000,
  56};
  57
  58static const struct regulator_ops hi6421v530_ldo_ops;
  59
  60#define HI6421V530_LDO_ENABLE_TIME (350)
  61
  62/*
  63 * _id - LDO id name string
  64 * v_table - voltage table
  65 * vreg - voltage select register
  66 * vmask - voltage select mask
  67 * ereg - enable register
  68 * emask - enable mask
  69 * odelay - off/on delay time in uS
  70 * ecomask - eco mode mask
  71 * ecoamp - eco mode load uppler limit in uA
  72 */
  73#define HI6421V530_LDO(_ID, v_table, vreg, vmask, ereg, emask,          \
  74                   odelay, ecomask, ecoamp) {                           \
  75        .rdesc = {                                                      \
  76                .name            = #_ID,                                \
  77                .of_match        = of_match_ptr(#_ID),                  \
  78                .regulators_node = of_match_ptr("regulators"),          \
  79                .ops             = &hi6421v530_ldo_ops,                 \
  80                .type            = REGULATOR_VOLTAGE,                   \
  81                .id              = HI6421V530_##_ID,                    \
  82                .owner           = THIS_MODULE,                         \
  83                .n_voltages      = ARRAY_SIZE(v_table),                 \
  84                .volt_table      = v_table,                             \
  85                .vsel_reg        = HI6421_REG_TO_BUS_ADDR(vreg),        \
  86                .vsel_mask       = vmask,                               \
  87                .enable_reg      = HI6421_REG_TO_BUS_ADDR(ereg),        \
  88                .enable_mask     = emask,                               \
  89                .enable_time     = HI6421V530_LDO_ENABLE_TIME,          \
  90                .off_on_delay    = odelay,                              \
  91        },                                                              \
  92        .mode_mask      = ecomask,                                      \
  93        .eco_microamp   = ecoamp,                                       \
  94}
  95
  96/* HI6421V530 regulator information */
  97
  98static struct hi6421v530_regulator_info hi6421v530_regulator_info[] = {
  99        HI6421V530_LDO(LDO3, ldo_3_voltages, 0x061, 0xf, 0x060, 0x2,
 100                   20000, 0x6, 8000),
 101        HI6421V530_LDO(LDO9, ldo_9_11_voltages, 0x06b, 0x7, 0x06a, 0x2,
 102                   40000, 0x6, 8000),
 103        HI6421V530_LDO(LDO11, ldo_9_11_voltages, 0x06f, 0x7, 0x06e, 0x2,
 104                   40000, 0x6, 8000),
 105        HI6421V530_LDO(LDO15, ldo_15_16_voltages, 0x077, 0x7, 0x076, 0x2,
 106                   40000, 0x6, 8000),
 107        HI6421V530_LDO(LDO16, ldo_15_16_voltages, 0x079, 0x7, 0x078, 0x2,
 108                   40000, 0x6, 8000),
 109};
 110
 111static unsigned int hi6421v530_regulator_ldo_get_mode(
 112                                        struct regulator_dev *rdev)
 113{
 114        struct hi6421v530_regulator_info *info;
 115        unsigned int reg_val;
 116
 117        info = rdev_get_drvdata(rdev);
 118        regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
 119
 120        if (reg_val & (info->mode_mask))
 121                return REGULATOR_MODE_IDLE;
 122
 123        return REGULATOR_MODE_NORMAL;
 124}
 125
 126static int hi6421v530_regulator_ldo_set_mode(struct regulator_dev *rdev,
 127                                                unsigned int mode)
 128{
 129        struct hi6421v530_regulator_info *info;
 130        unsigned int new_mode;
 131
 132        info = rdev_get_drvdata(rdev);
 133        switch (mode) {
 134        case REGULATOR_MODE_NORMAL:
 135                new_mode = 0;
 136                break;
 137        case REGULATOR_MODE_IDLE:
 138                new_mode = info->mode_mask;
 139                break;
 140        default:
 141                return -EINVAL;
 142        }
 143
 144        regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 145                           info->mode_mask, new_mode);
 146
 147        return 0;
 148}
 149
 150
 151static const struct regulator_ops hi6421v530_ldo_ops = {
 152        .is_enabled = regulator_is_enabled_regmap,
 153        .enable = regulator_enable_regmap,
 154        .disable = regulator_disable_regmap,
 155        .list_voltage = regulator_list_voltage_table,
 156        .map_voltage = regulator_map_voltage_ascend,
 157        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 158        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 159        .get_mode = hi6421v530_regulator_ldo_get_mode,
 160        .set_mode = hi6421v530_regulator_ldo_set_mode,
 161};
 162
 163static int hi6421v530_regulator_probe(struct platform_device *pdev)
 164{
 165        struct hi6421_pmic *pmic;
 166        struct regulator_dev *rdev;
 167        struct regulator_config config = { };
 168        unsigned int i;
 169
 170        pmic = dev_get_drvdata(pdev->dev.parent);
 171        if (!pmic) {
 172                dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
 173                return -ENODEV;
 174        }
 175
 176        for (i = 0; i < ARRAY_SIZE(hi6421v530_regulator_info); i++) {
 177                config.dev = pdev->dev.parent;
 178                config.regmap = pmic->regmap;
 179                config.driver_data = &hi6421v530_regulator_info[i];
 180
 181                rdev = devm_regulator_register(&pdev->dev,
 182                                &hi6421v530_regulator_info[i].rdesc,
 183                                &config);
 184                if (IS_ERR(rdev)) {
 185                        dev_err(&pdev->dev, "failed to register regulator %s\n",
 186                                hi6421v530_regulator_info[i].rdesc.name);
 187                        return PTR_ERR(rdev);
 188                }
 189        }
 190        return 0;
 191}
 192
 193static const struct platform_device_id hi6421v530_regulator_table[] = {
 194        { .name = "hi6421v530-regulator" },
 195        {},
 196};
 197MODULE_DEVICE_TABLE(platform, hi6421v530_regulator_table);
 198
 199static struct platform_driver hi6421v530_regulator_driver = {
 200        .id_table = hi6421v530_regulator_table,
 201        .driver = {
 202                .name   = "hi6421v530-regulator",
 203        },
 204        .probe  = hi6421v530_regulator_probe,
 205};
 206module_platform_driver(hi6421v530_regulator_driver);
 207
 208MODULE_AUTHOR("Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>");
 209MODULE_DESCRIPTION("Hi6421v530 regulator driver");
 210MODULE_LICENSE("GPL v2");
 211