linux/drivers/regulator/mt6380-regulator.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017 MediaTek Inc.
   3 * Author: Chenglin Xu <chenglin.xu@mediatek.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/of.h>
  17#include <linux/platform_device.h>
  18#include <linux/regmap.h>
  19#include <linux/regulator/driver.h>
  20#include <linux/regulator/machine.h>
  21#include <linux/regulator/mt6380-regulator.h>
  22#include <linux/regulator/of_regulator.h>
  23
  24/* PMIC Registers */
  25#define MT6380_ALDO_CON_0                         0x0000
  26#define MT6380_BTLDO_CON_0                        0x0004
  27#define MT6380_COMP_CON_0                         0x0008
  28#define MT6380_CPUBUCK_CON_0                      0x000C
  29#define MT6380_CPUBUCK_CON_1                      0x0010
  30#define MT6380_CPUBUCK_CON_2                      0x0014
  31#define MT6380_DDRLDO_CON_0                       0x0018
  32#define MT6380_MLDO_CON_0                         0x001C
  33#define MT6380_PALDO_CON_0                        0x0020
  34#define MT6380_PHYLDO_CON_0                       0x0024
  35#define MT6380_SIDO_CON_0                         0x0028
  36#define MT6380_SIDO_CON_1                         0x002C
  37#define MT6380_SIDO_CON_2                         0x0030
  38#define MT6380_SLDO_CON_0                         0x0034
  39#define MT6380_TLDO_CON_0                         0x0038
  40#define MT6380_STARTUP_CON_0                      0x003C
  41#define MT6380_STARTUP_CON_1                      0x0040
  42#define MT6380_SMPS_TOP_CON_0                     0x0044
  43#define MT6380_SMPS_TOP_CON_1                     0x0048
  44#define MT6380_ANA_CTRL_0                         0x0050
  45#define MT6380_ANA_CTRL_1                         0x0054
  46#define MT6380_ANA_CTRL_2                         0x0058
  47#define MT6380_ANA_CTRL_3                         0x005C
  48#define MT6380_ANA_CTRL_4                         0x0060
  49#define MT6380_SPK_CON9                           0x0064
  50#define MT6380_SPK_CON11                          0x0068
  51#define MT6380_SPK_CON12                          0x006A
  52#define MT6380_CLK_CTRL                           0x0070
  53#define MT6380_PINMUX_CTRL                        0x0074
  54#define MT6380_IO_CTRL                            0x0078
  55#define MT6380_SLP_MODE_CTRL_0                    0x007C
  56#define MT6380_SLP_MODE_CTRL_1                    0x0080
  57#define MT6380_SLP_MODE_CTRL_2                    0x0084
  58#define MT6380_SLP_MODE_CTRL_3                    0x0088
  59#define MT6380_SLP_MODE_CTRL_4                    0x008C
  60#define MT6380_SLP_MODE_CTRL_5                    0x0090
  61#define MT6380_SLP_MODE_CTRL_6                    0x0094
  62#define MT6380_SLP_MODE_CTRL_7                    0x0098
  63#define MT6380_SLP_MODE_CTRL_8                    0x009C
  64#define MT6380_FCAL_CTRL_0                        0x00A0
  65#define MT6380_FCAL_CTRL_1                        0x00A4
  66#define MT6380_LDO_CTRL_0                         0x00A8
  67#define MT6380_LDO_CTRL_1                         0x00AC
  68#define MT6380_LDO_CTRL_2                         0x00B0
  69#define MT6380_LDO_CTRL_3                         0x00B4
  70#define MT6380_LDO_CTRL_4                         0x00B8
  71#define MT6380_DEBUG_CTRL_0                       0x00BC
  72#define MT6380_EFU_CTRL_0                         0x0200
  73#define MT6380_EFU_CTRL_1                         0x0201
  74#define MT6380_EFU_CTRL_2                         0x0202
  75#define MT6380_EFU_CTRL_3                         0x0203
  76#define MT6380_EFU_CTRL_4                         0x0204
  77#define MT6380_EFU_CTRL_5                         0x0205
  78#define MT6380_EFU_CTRL_6                         0x0206
  79#define MT6380_EFU_CTRL_7                         0x0207
  80#define MT6380_EFU_CTRL_8                         0x0208
  81
  82#define MT6380_REGULATOR_MODE_AUTO      0
  83#define MT6380_REGULATOR_MODE_FORCE_PWM 1
  84
  85/*
  86 * mt6380 regulators' information
  87 *
  88 * @desc: standard fields of regulator description
  89 * @vselon_reg: Register sections for hardware control mode of bucks
  90 * @modeset_reg: Register for controlling the buck/LDO control mode
  91 * @modeset_mask: Mask for controlling the buck/LDO control mode
  92 */
  93struct mt6380_regulator_info {
  94        struct regulator_desc desc;
  95        u32 vselon_reg;
  96        u32 modeset_reg;
  97        u32 modeset_mask;
  98};
  99
 100#define MT6380_BUCK(match, vreg, min, max, step, volt_ranges, enreg,    \
 101                    vosel, vosel_mask, enbit, voselon, _modeset_reg,    \
 102                    _modeset_mask)                                      \
 103[MT6380_ID_##vreg] = {                                                  \
 104        .desc = {                                                       \
 105                .name = #vreg,                                          \
 106                .of_match = of_match_ptr(match),                        \
 107                .ops = &mt6380_volt_range_ops,                          \
 108                .type = REGULATOR_VOLTAGE,                              \
 109                .id = MT6380_ID_##vreg,                                 \
 110                .owner = THIS_MODULE,                                   \
 111                .n_voltages = ((max) - (min)) / (step) + 1,             \
 112                .linear_ranges = volt_ranges,                           \
 113                .n_linear_ranges = ARRAY_SIZE(volt_ranges),             \
 114                .vsel_reg = vosel,                                      \
 115                .vsel_mask = vosel_mask,                                \
 116                .enable_reg = enreg,                                    \
 117                .enable_mask = BIT(enbit),                              \
 118        },                                                              \
 119        .vselon_reg = voselon,                                          \
 120        .modeset_reg = _modeset_reg,                                    \
 121        .modeset_mask = _modeset_mask,                                  \
 122}
 123
 124#define MT6380_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel,    \
 125                   vosel_mask, _modeset_reg, _modeset_mask)             \
 126[MT6380_ID_##vreg] = {                                                  \
 127        .desc = {                                                       \
 128                .name = #vreg,                                          \
 129                .of_match = of_match_ptr(match),                        \
 130                .ops = &mt6380_volt_table_ops,                          \
 131                .type = REGULATOR_VOLTAGE,                              \
 132                .id = MT6380_ID_##vreg,                                 \
 133                .owner = THIS_MODULE,                                   \
 134                .n_voltages = ARRAY_SIZE(ldo_volt_table),               \
 135                .volt_table = ldo_volt_table,                           \
 136                .vsel_reg = vosel,                                      \
 137                .vsel_mask = vosel_mask,                                \
 138                .enable_reg = enreg,                                    \
 139                .enable_mask = BIT(enbit),                              \
 140        },                                                              \
 141        .modeset_reg = _modeset_reg,                                    \
 142        .modeset_mask = _modeset_mask,                                  \
 143}
 144
 145#define MT6380_REG_FIXED(match, vreg, enreg, enbit, volt,               \
 146                         _modeset_reg, _modeset_mask)                   \
 147[MT6380_ID_##vreg] = {                                                  \
 148        .desc = {                                                       \
 149                .name = #vreg,                                          \
 150                .of_match = of_match_ptr(match),                        \
 151                .ops = &mt6380_volt_fixed_ops,                          \
 152                .type = REGULATOR_VOLTAGE,                              \
 153                .id = MT6380_ID_##vreg,                                 \
 154                .owner = THIS_MODULE,                                   \
 155                .n_voltages = 1,                                        \
 156                .enable_reg = enreg,                                    \
 157                .enable_mask = BIT(enbit),                              \
 158                .min_uV = volt,                                         \
 159        },                                                              \
 160        .modeset_reg = _modeset_reg,                                    \
 161        .modeset_mask = _modeset_mask,                                  \
 162}
 163
 164static const struct regulator_linear_range buck_volt_range1[] = {
 165        REGULATOR_LINEAR_RANGE(600000, 0, 0xfe, 6250),
 166};
 167
 168static const struct regulator_linear_range buck_volt_range2[] = {
 169        REGULATOR_LINEAR_RANGE(600000, 0, 0xfe, 6250),
 170};
 171
 172static const struct regulator_linear_range buck_volt_range3[] = {
 173        REGULATOR_LINEAR_RANGE(1200000, 0, 0x3c, 25000),
 174};
 175
 176static const u32 ldo_volt_table1[] = {
 177        1400000, 1350000, 1300000, 1250000, 1200000, 1150000, 1100000, 1050000,
 178};
 179
 180static const u32 ldo_volt_table2[] = {
 181        2200000, 3300000,
 182};
 183
 184static const u32 ldo_volt_table3[] = {
 185        1240000, 1390000, 1540000, 1840000,
 186};
 187
 188static const u32 ldo_volt_table4[] = {
 189        2200000, 3300000,
 190};
 191
 192static int mt6380_regulator_set_mode(struct regulator_dev *rdev,
 193                                     unsigned int mode)
 194{
 195        int ret, val = 0;
 196        struct mt6380_regulator_info *info = rdev_get_drvdata(rdev);
 197
 198        switch (mode) {
 199        case REGULATOR_MODE_NORMAL:
 200                val = MT6380_REGULATOR_MODE_AUTO;
 201                break;
 202        case REGULATOR_MODE_FAST:
 203                val = MT6380_REGULATOR_MODE_FORCE_PWM;
 204                break;
 205        default:
 206                return -EINVAL;
 207        }
 208
 209        val <<= ffs(info->modeset_mask) - 1;
 210
 211        ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
 212                                 info->modeset_mask, val);
 213
 214        return ret;
 215}
 216
 217static unsigned int mt6380_regulator_get_mode(struct regulator_dev *rdev)
 218{
 219        unsigned int val;
 220        unsigned int mode;
 221        int ret;
 222        struct mt6380_regulator_info *info = rdev_get_drvdata(rdev);
 223
 224        ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
 225        if (ret < 0)
 226                return ret;
 227
 228        val &= info->modeset_mask;
 229        val >>= ffs(info->modeset_mask) - 1;
 230
 231        switch (val) {
 232        case MT6380_REGULATOR_MODE_AUTO:
 233                mode = REGULATOR_MODE_NORMAL;
 234                break;
 235        case MT6380_REGULATOR_MODE_FORCE_PWM:
 236                mode = REGULATOR_MODE_FAST;
 237                break;
 238        default:
 239                return -EINVAL;
 240        }
 241
 242        return mode;
 243}
 244
 245static const struct regulator_ops mt6380_volt_range_ops = {
 246        .list_voltage = regulator_list_voltage_linear_range,
 247        .map_voltage = regulator_map_voltage_linear_range,
 248        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 249        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 250        .set_voltage_time_sel = regulator_set_voltage_time_sel,
 251        .enable = regulator_enable_regmap,
 252        .disable = regulator_disable_regmap,
 253        .is_enabled = regulator_is_enabled_regmap,
 254        .set_mode = mt6380_regulator_set_mode,
 255        .get_mode = mt6380_regulator_get_mode,
 256};
 257
 258static const struct regulator_ops mt6380_volt_table_ops = {
 259        .list_voltage = regulator_list_voltage_table,
 260        .map_voltage = regulator_map_voltage_iterate,
 261        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 262        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 263        .set_voltage_time_sel = regulator_set_voltage_time_sel,
 264        .enable = regulator_enable_regmap,
 265        .disable = regulator_disable_regmap,
 266        .is_enabled = regulator_is_enabled_regmap,
 267        .set_mode = mt6380_regulator_set_mode,
 268        .get_mode = mt6380_regulator_get_mode,
 269};
 270
 271static const struct regulator_ops mt6380_volt_fixed_ops = {
 272        .list_voltage = regulator_list_voltage_linear,
 273        .enable = regulator_enable_regmap,
 274        .disable = regulator_disable_regmap,
 275        .is_enabled = regulator_is_enabled_regmap,
 276        .set_mode = mt6380_regulator_set_mode,
 277        .get_mode = mt6380_regulator_get_mode,
 278};
 279
 280/* The array is indexed by id(MT6380_ID_XXX) */
 281static struct mt6380_regulator_info mt6380_regulators[] = {
 282        MT6380_BUCK("buck-vcore1", VCPU, 600000, 1393750, 6250,
 283                    buck_volt_range1, MT6380_ANA_CTRL_3, MT6380_ANA_CTRL_1,
 284                    0xfe, 3, MT6380_ANA_CTRL_1,
 285                    MT6380_CPUBUCK_CON_0, 0x8000000),
 286        MT6380_BUCK("buck-vcore", VCORE, 600000, 1393750, 6250,
 287                    buck_volt_range2, MT6380_ANA_CTRL_3, MT6380_ANA_CTRL_2,
 288                    0xfe, 2, MT6380_ANA_CTRL_2, MT6380_SIDO_CON_0, 0x1000000),
 289        MT6380_BUCK("buck-vrf", VRF, 1200000, 1575000, 25000,
 290                    buck_volt_range3, MT6380_ANA_CTRL_3, MT6380_SIDO_CON_0,
 291                    0x78, 1, MT6380_SIDO_CON_0, MT6380_SIDO_CON_0, 0x8000),
 292        MT6380_LDO("ldo-vm", VMLDO, ldo_volt_table1, MT6380_LDO_CTRL_0,
 293                   1, MT6380_MLDO_CON_0, 0xE000, MT6380_ANA_CTRL_1, 0x4000000),
 294        MT6380_LDO("ldo-va", VALDO, ldo_volt_table2, MT6380_LDO_CTRL_0,
 295                   2, MT6380_ALDO_CON_0, 0x400, MT6380_ALDO_CON_0, 0x20),
 296        MT6380_REG_FIXED("ldo-vphy", VPHYLDO, MT6380_LDO_CTRL_0, 7, 1800000,
 297                         MT6380_PHYLDO_CON_0, 0x80),
 298        MT6380_LDO("ldo-vddr", VDDRLDO, ldo_volt_table3, MT6380_LDO_CTRL_0,
 299                   8, MT6380_DDRLDO_CON_0, 0x3000, MT6380_DDRLDO_CON_0, 0x80),
 300        MT6380_LDO("ldo-vt", VTLDO, ldo_volt_table4, MT6380_LDO_CTRL_0, 3,
 301                   MT6380_TLDO_CON_0, 0x400, MT6380_TLDO_CON_0, 0x20),
 302};
 303
 304static int mt6380_regulator_probe(struct platform_device *pdev)
 305{
 306        struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
 307        struct regulator_config config = {};
 308        struct regulator_dev *rdev;
 309        int i;
 310
 311        for (i = 0; i < MT6380_MAX_REGULATOR; i++) {
 312                config.dev = &pdev->dev;
 313                config.driver_data = &mt6380_regulators[i];
 314                config.regmap = regmap;
 315                rdev = devm_regulator_register(&pdev->dev,
 316                                               &mt6380_regulators[i].desc,
 317                                &config);
 318                if (IS_ERR(rdev)) {
 319                        dev_err(&pdev->dev, "failed to register %s\n",
 320                                mt6380_regulators[i].desc.name);
 321                        return PTR_ERR(rdev);
 322                }
 323        }
 324        return 0;
 325}
 326
 327static const struct platform_device_id mt6380_platform_ids[] = {
 328        {"mt6380-regulator", 0},
 329        { /* sentinel */ },
 330};
 331MODULE_DEVICE_TABLE(platform, mt6380_platform_ids);
 332
 333static const struct of_device_id mt6380_of_match[] = {
 334        { .compatible = "mediatek,mt6380-regulator", },
 335        { /* sentinel */ },
 336};
 337MODULE_DEVICE_TABLE(of, mt6380_of_match);
 338
 339static struct platform_driver mt6380_regulator_driver = {
 340        .driver = {
 341                .name = "mt6380-regulator",
 342                .of_match_table = of_match_ptr(mt6380_of_match),
 343        },
 344        .probe = mt6380_regulator_probe,
 345        .id_table = mt6380_platform_ids,
 346};
 347
 348module_platform_driver(mt6380_regulator_driver);
 349
 350MODULE_AUTHOR("Chenglin Xu <chenglin.xu@mediatek.com>");
 351MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6380 PMIC");
 352MODULE_LICENSE("GPL v2");
 353