linux/drivers/regulator/hi655x-regulator.c
<<
>>
Prefs
   1/*
   2 * Device driver for regulators in Hi655x IC
   3 *
   4 * Copyright (c) 2016 Hisilicon.
   5 *
   6 * Authors:
   7 * Chen Feng <puck.chen@hisilicon.com>
   8 * Fei  Wang <w.f@huawei.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/bitops.h>
  16#include <linux/device.h>
  17#include <linux/err.h>
  18#include <linux/module.h>
  19#include <linux/io.h>
  20#include <linux/of.h>
  21#include <linux/platform_device.h>
  22#include <linux/regmap.h>
  23#include <linux/regulator/driver.h>
  24#include <linux/regulator/machine.h>
  25#include <linux/regulator/of_regulator.h>
  26#include <linux/mfd/hi655x-pmic.h>
  27
  28struct hi655x_regulator {
  29        unsigned int disable_reg;
  30        unsigned int status_reg;
  31        unsigned int ctrl_regs;
  32        unsigned int ctrl_mask;
  33        struct regulator_desc rdesc;
  34};
  35
  36/* LDO7 & LDO10 */
  37static const unsigned int ldo7_voltages[] = {
  38        1800000, 1850000, 2850000, 2900000,
  39        3000000, 3100000, 3200000, 3300000,
  40};
  41
  42static const unsigned int ldo19_voltages[] = {
  43        1800000, 1850000, 1900000, 1750000,
  44        2800000, 2850000, 2900000, 3000000,
  45};
  46
  47static const unsigned int ldo22_voltages[] = {
  48         900000, 1000000, 1050000, 1100000,
  49        1150000, 1175000, 1185000, 1200000,
  50};
  51
  52enum hi655x_regulator_id {
  53        HI655X_LDO0,
  54        HI655X_LDO1,
  55        HI655X_LDO2,
  56        HI655X_LDO3,
  57        HI655X_LDO4,
  58        HI655X_LDO5,
  59        HI655X_LDO6,
  60        HI655X_LDO7,
  61        HI655X_LDO8,
  62        HI655X_LDO9,
  63        HI655X_LDO10,
  64        HI655X_LDO11,
  65        HI655X_LDO12,
  66        HI655X_LDO13,
  67        HI655X_LDO14,
  68        HI655X_LDO15,
  69        HI655X_LDO16,
  70        HI655X_LDO17,
  71        HI655X_LDO18,
  72        HI655X_LDO19,
  73        HI655X_LDO20,
  74        HI655X_LDO21,
  75        HI655X_LDO22,
  76};
  77
  78static int hi655x_is_enabled(struct regulator_dev *rdev)
  79{
  80        unsigned int value = 0;
  81
  82        struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
  83
  84        regmap_read(rdev->regmap, regulator->status_reg, &value);
  85        return (value & BIT(regulator->ctrl_mask));
  86}
  87
  88static int hi655x_disable(struct regulator_dev *rdev)
  89{
  90        int ret = 0;
  91
  92        struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
  93
  94        ret = regmap_write(rdev->regmap, regulator->disable_reg,
  95                           BIT(regulator->ctrl_mask));
  96        return ret;
  97}
  98
  99static const struct regulator_ops hi655x_regulator_ops = {
 100        .enable = regulator_enable_regmap,
 101        .disable = hi655x_disable,
 102        .is_enabled = hi655x_is_enabled,
 103        .list_voltage = regulator_list_voltage_table,
 104        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 105        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 106};
 107
 108static const struct regulator_ops hi655x_ldo_linear_ops = {
 109        .enable = regulator_enable_regmap,
 110        .disable = hi655x_disable,
 111        .is_enabled = hi655x_is_enabled,
 112        .list_voltage = regulator_list_voltage_linear,
 113        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 114        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 115};
 116
 117#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg,                 \
 118                   sreg, cmask, vtable) {                        \
 119        .rdesc = {                                               \
 120                .name            = #_ID,                         \
 121                .of_match        = of_match_ptr(#_ID),           \
 122                .ops             = &hi655x_regulator_ops,        \
 123                .regulators_node = of_match_ptr("regulators"),   \
 124                .type            = REGULATOR_VOLTAGE,            \
 125                .id              = HI655X_##_ID,                 \
 126                .owner           = THIS_MODULE,                  \
 127                .n_voltages      = ARRAY_SIZE(vtable),           \
 128                .volt_table      = vtable,                       \
 129                .vsel_reg        = HI655X_BUS_ADDR(vreg),        \
 130                .vsel_mask       = vmask,                        \
 131                .enable_reg      = HI655X_BUS_ADDR(ereg),        \
 132                .enable_mask     = BIT(cmask),                   \
 133        },                                                       \
 134        .disable_reg = HI655X_BUS_ADDR(dreg),                    \
 135        .status_reg = HI655X_BUS_ADDR(sreg),                     \
 136        .ctrl_mask = cmask,                                      \
 137}
 138
 139#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg,          \
 140                          sreg, cmask, minv, nvolt, vstep) {     \
 141        .rdesc = {                                               \
 142                .name            = #_ID,                         \
 143                .of_match        = of_match_ptr(#_ID),           \
 144                .ops             = &hi655x_ldo_linear_ops,       \
 145                .regulators_node = of_match_ptr("regulators"),   \
 146                .type            = REGULATOR_VOLTAGE,            \
 147                .id              = HI655X_##_ID,                 \
 148                .owner           = THIS_MODULE,                  \
 149                .min_uV          = minv,                         \
 150                .n_voltages      = nvolt,                        \
 151                .uV_step         = vstep,                        \
 152                .vsel_reg        = HI655X_BUS_ADDR(vreg),        \
 153                .vsel_mask       = vmask,                        \
 154                .enable_reg      = HI655X_BUS_ADDR(ereg),        \
 155                .enable_mask     = BIT(cmask),                   \
 156        },                                                       \
 157        .disable_reg = HI655X_BUS_ADDR(dreg),                    \
 158        .status_reg = HI655X_BUS_ADDR(sreg),                     \
 159        .ctrl_mask = cmask,                                      \
 160}
 161
 162static struct hi655x_regulator regulators[] = {
 163        HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01,
 164                          2500000, 8, 100000),
 165        HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages),
 166        HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages),
 167        HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04,
 168                          1600000, 8, 50000),
 169        HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05,
 170                          2500000, 8, 100000),
 171        HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06,
 172                          1600000, 8, 50000),
 173        HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00,
 174                          2500000, 8, 100000),
 175        HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages),
 176        HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04,
 177                          1650000, 8, 50000),
 178        HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages),
 179};
 180
 181static int hi655x_regulator_probe(struct platform_device *pdev)
 182{
 183        unsigned int i;
 184        struct hi655x_regulator *regulator;
 185        struct hi655x_pmic *pmic;
 186        struct regulator_config config = { };
 187        struct regulator_dev *rdev;
 188
 189        pmic = dev_get_drvdata(pdev->dev.parent);
 190        if (!pmic) {
 191                dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
 192                return -ENODEV;
 193        }
 194
 195        regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
 196        if (!regulator)
 197                return -ENOMEM;
 198
 199        platform_set_drvdata(pdev, regulator);
 200
 201        config.dev = pdev->dev.parent;
 202        config.regmap = pmic->regmap;
 203        config.driver_data = regulator;
 204        for (i = 0; i < ARRAY_SIZE(regulators); i++) {
 205                rdev = devm_regulator_register(&pdev->dev,
 206                                               &regulators[i].rdesc,
 207                                               &config);
 208                if (IS_ERR(rdev)) {
 209                        dev_err(&pdev->dev, "failed to register regulator %s\n",
 210                                regulator->rdesc.name);
 211                        return PTR_ERR(rdev);
 212                }
 213        }
 214        return 0;
 215}
 216
 217static const struct platform_device_id hi655x_regulator_table[] = {
 218        { .name = "hi655x-regulator" },
 219        {},
 220};
 221MODULE_DEVICE_TABLE(platform, hi655x_regulator_table);
 222
 223static struct platform_driver hi655x_regulator_driver = {
 224        .id_table = hi655x_regulator_table,
 225        .driver = {
 226                .name   = "hi655x-regulator",
 227        },
 228        .probe  = hi655x_regulator_probe,
 229};
 230module_platform_driver(hi655x_regulator_driver);
 231
 232MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
 233MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver");
 234MODULE_LICENSE("GPL v2");
 235