linux/drivers/regulator/tps65090-regulator.c
<<
>>
Prefs
   1/*
   2 * Regulator driver for tps65090 power management chip.
   3 *
   4 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
   5
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/init.h>
  21#include <linux/gpio.h>
  22#include <linux/of_gpio.h>
  23#include <linux/slab.h>
  24#include <linux/err.h>
  25#include <linux/platform_device.h>
  26#include <linux/regulator/driver.h>
  27#include <linux/regulator/machine.h>
  28#include <linux/regulator/of_regulator.h>
  29#include <linux/mfd/tps65090.h>
  30
  31struct tps65090_regulator {
  32        struct device           *dev;
  33        struct regulator_desc   *desc;
  34        struct regulator_dev    *rdev;
  35};
  36
  37static struct regulator_ops tps65090_ext_control_ops = {
  38};
  39
  40static struct regulator_ops tps65090_reg_contol_ops = {
  41        .enable         = regulator_enable_regmap,
  42        .disable        = regulator_disable_regmap,
  43        .is_enabled     = regulator_is_enabled_regmap,
  44};
  45
  46static struct regulator_ops tps65090_ldo_ops = {
  47};
  48
  49#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)   \
  50{                                                       \
  51        .name = "TPS65090_RAILS"#_id,                   \
  52        .supply_name = _sname,                          \
  53        .id = TPS65090_REGULATOR_##_id,                 \
  54        .ops = &_ops,                                   \
  55        .enable_reg = _en_reg,                          \
  56        .enable_mask = BIT(0),                          \
  57        .type = REGULATOR_VOLTAGE,                      \
  58        .owner = THIS_MODULE,                           \
  59}
  60
  61static struct regulator_desc tps65090_regulator_desc[] = {
  62        tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_reg_contol_ops),
  63        tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_reg_contol_ops),
  64        tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_reg_contol_ops),
  65        tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_reg_contol_ops),
  66        tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_reg_contol_ops),
  67        tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_reg_contol_ops),
  68        tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_reg_contol_ops),
  69        tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
  70        tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
  71        tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
  72        tps65090_REG_DESC(LDO1,  "vsys-l1", 0,    tps65090_ldo_ops),
  73        tps65090_REG_DESC(LDO2,  "vsys-l2", 0,    tps65090_ldo_ops),
  74};
  75
  76static inline bool is_dcdc(int id)
  77{
  78        switch (id) {
  79        case TPS65090_REGULATOR_DCDC1:
  80        case TPS65090_REGULATOR_DCDC2:
  81        case TPS65090_REGULATOR_DCDC3:
  82                return true;
  83        default:
  84                return false;
  85        }
  86}
  87
  88static int tps65090_config_ext_control(
  89        struct tps65090_regulator *ri, bool enable)
  90{
  91        int ret;
  92        struct device *parent = ri->dev->parent;
  93        unsigned int reg_en_reg = ri->desc->enable_reg;
  94
  95        if (enable)
  96                ret = tps65090_set_bits(parent, reg_en_reg, 1);
  97        else
  98                ret =  tps65090_clr_bits(parent, reg_en_reg, 1);
  99        if (ret < 0)
 100                dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg);
 101        return ret;
 102}
 103
 104static int tps65090_regulator_disable_ext_control(
 105                struct tps65090_regulator *ri,
 106                struct tps65090_regulator_plat_data *tps_pdata)
 107{
 108        int ret = 0;
 109        struct device *parent = ri->dev->parent;
 110        unsigned int reg_en_reg = ri->desc->enable_reg;
 111
 112        /*
 113         * First enable output for internal control if require.
 114         * And then disable external control.
 115         */
 116        if (tps_pdata->reg_init_data->constraints.always_on ||
 117                        tps_pdata->reg_init_data->constraints.boot_on) {
 118                ret =  tps65090_set_bits(parent, reg_en_reg, 0);
 119                if (ret < 0) {
 120                        dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg);
 121                        return ret;
 122                }
 123        }
 124        return tps65090_config_ext_control(ri, false);
 125}
 126
 127static void tps65090_configure_regulator_config(
 128                struct tps65090_regulator_plat_data *tps_pdata,
 129                struct regulator_config *config)
 130{
 131        if (gpio_is_valid(tps_pdata->gpio)) {
 132                int gpio_flag = GPIOF_OUT_INIT_LOW;
 133
 134                if (tps_pdata->reg_init_data->constraints.always_on ||
 135                                tps_pdata->reg_init_data->constraints.boot_on)
 136                        gpio_flag = GPIOF_OUT_INIT_HIGH;
 137
 138                config->ena_gpio = tps_pdata->gpio;
 139                config->ena_gpio_flags = gpio_flag;
 140        }
 141}
 142
 143#ifdef CONFIG_OF
 144static struct of_regulator_match tps65090_matches[] = {
 145        { .name = "dcdc1", },
 146        { .name = "dcdc2", },
 147        { .name = "dcdc3", },
 148        { .name = "fet1",  },
 149        { .name = "fet2",  },
 150        { .name = "fet3",  },
 151        { .name = "fet4",  },
 152        { .name = "fet5",  },
 153        { .name = "fet6",  },
 154        { .name = "fet7",  },
 155        { .name = "ldo1",  },
 156        { .name = "ldo2",  },
 157};
 158
 159static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 160                struct platform_device *pdev,
 161                struct of_regulator_match **tps65090_reg_matches)
 162{
 163        struct tps65090_platform_data *tps65090_pdata;
 164        struct device_node *np = pdev->dev.parent->of_node;
 165        struct device_node *regulators;
 166        int idx = 0, ret;
 167        struct tps65090_regulator_plat_data *reg_pdata;
 168
 169        tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
 170                                GFP_KERNEL);
 171        if (!tps65090_pdata) {
 172                dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
 173                return ERR_PTR(-ENOMEM);
 174        }
 175
 176        reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
 177                                sizeof(*reg_pdata), GFP_KERNEL);
 178        if (!reg_pdata) {
 179                dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
 180                return ERR_PTR(-ENOMEM);
 181        }
 182
 183        regulators = of_find_node_by_name(np, "regulators");
 184        if (!regulators) {
 185                dev_err(&pdev->dev, "regulator node not found\n");
 186                return ERR_PTR(-ENODEV);
 187        }
 188
 189        ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
 190                        ARRAY_SIZE(tps65090_matches));
 191        if (ret < 0) {
 192                dev_err(&pdev->dev,
 193                        "Error parsing regulator init data: %d\n", ret);
 194                return ERR_PTR(ret);
 195        }
 196
 197        *tps65090_reg_matches = tps65090_matches;
 198        for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) {
 199                struct regulator_init_data *ri_data;
 200                struct tps65090_regulator_plat_data *rpdata;
 201
 202                rpdata = &reg_pdata[idx];
 203                ri_data = tps65090_matches[idx].init_data;
 204                if (!ri_data || !tps65090_matches[idx].of_node)
 205                        continue;
 206
 207                rpdata->reg_init_data = ri_data;
 208                rpdata->enable_ext_control = of_property_read_bool(
 209                                        tps65090_matches[idx].of_node,
 210                                        "ti,enable-ext-control");
 211                if (rpdata->enable_ext_control)
 212                        rpdata->gpio = of_get_named_gpio(np,
 213                                        "dcdc-ext-control-gpios", 0);
 214
 215                tps65090_pdata->reg_pdata[idx] = rpdata;
 216        }
 217        return tps65090_pdata;
 218}
 219#else
 220static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data(
 221                        struct platform_device *pdev,
 222                        struct of_regulator_match **tps65090_reg_matches)
 223{
 224        *tps65090_reg_matches = NULL;
 225        return NULL;
 226}
 227#endif
 228
 229static int tps65090_regulator_probe(struct platform_device *pdev)
 230{
 231        struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
 232        struct tps65090_regulator *ri = NULL;
 233        struct regulator_config config = { };
 234        struct regulator_dev *rdev;
 235        struct tps65090_regulator_plat_data *tps_pdata;
 236        struct tps65090_regulator *pmic;
 237        struct tps65090_platform_data *tps65090_pdata;
 238        struct of_regulator_match *tps65090_reg_matches = NULL;
 239        int num;
 240        int ret;
 241
 242        dev_dbg(&pdev->dev, "Probing regulator\n");
 243
 244        tps65090_pdata = dev_get_platdata(pdev->dev.parent);
 245        if (!tps65090_pdata && tps65090_mfd->dev->of_node)
 246                tps65090_pdata = tps65090_parse_dt_reg_data(pdev,
 247                                        &tps65090_reg_matches);
 248        if (IS_ERR_OR_NULL(tps65090_pdata)) {
 249                dev_err(&pdev->dev, "Platform data missing\n");
 250                return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL;
 251        }
 252
 253        pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
 254                        GFP_KERNEL);
 255        if (!pmic) {
 256                dev_err(&pdev->dev, "mem alloc for pmic failed\n");
 257                return -ENOMEM;
 258        }
 259
 260        for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
 261                tps_pdata = tps65090_pdata->reg_pdata[num];
 262
 263                ri = &pmic[num];
 264                ri->dev = &pdev->dev;
 265                ri->desc = &tps65090_regulator_desc[num];
 266
 267                /*
 268                 * TPS5090 DCDC support the control from external digital input.
 269                 * Configure it as per platform data.
 270                 */
 271                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) {
 272                        if (tps_pdata->enable_ext_control) {
 273                                tps65090_configure_regulator_config(
 274                                                tps_pdata, &config);
 275                                ri->desc->ops = &tps65090_ext_control_ops;
 276                        } else {
 277                                ret = tps65090_regulator_disable_ext_control(
 278                                                ri, tps_pdata);
 279                                if (ret < 0) {
 280                                        dev_err(&pdev->dev,
 281                                                "failed disable ext control\n");
 282                                        goto scrub;
 283                                }
 284                        }
 285                }
 286
 287                config.dev = pdev->dev.parent;
 288                config.driver_data = ri;
 289                config.regmap = tps65090_mfd->rmap;
 290                if (tps_pdata)
 291                        config.init_data = tps_pdata->reg_init_data;
 292                else
 293                        config.init_data = NULL;
 294                if (tps65090_reg_matches)
 295                        config.of_node = tps65090_reg_matches[num].of_node;
 296                else
 297                        config.of_node = NULL;
 298
 299                rdev = regulator_register(ri->desc, &config);
 300                if (IS_ERR(rdev)) {
 301                        dev_err(&pdev->dev, "failed to register regulator %s\n",
 302                                ri->desc->name);
 303                        ret = PTR_ERR(rdev);
 304                        goto scrub;
 305                }
 306                ri->rdev = rdev;
 307
 308                /* Enable external control if it is require */
 309                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&
 310                                tps_pdata->enable_ext_control) {
 311                        ret = tps65090_config_ext_control(ri, true);
 312                        if (ret < 0) {
 313                                /* Increment num to get unregister rdev */
 314                                num++;
 315                                goto scrub;
 316                        }
 317                }
 318        }
 319
 320        platform_set_drvdata(pdev, pmic);
 321        return 0;
 322
 323scrub:
 324        while (--num >= 0) {
 325                ri = &pmic[num];
 326                regulator_unregister(ri->rdev);
 327        }
 328        return ret;
 329}
 330
 331static int tps65090_regulator_remove(struct platform_device *pdev)
 332{
 333        struct tps65090_regulator *pmic = platform_get_drvdata(pdev);
 334        struct tps65090_regulator *ri;
 335        int num;
 336
 337        for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) {
 338                ri = &pmic[num];
 339                regulator_unregister(ri->rdev);
 340        }
 341        return 0;
 342}
 343
 344static struct platform_driver tps65090_regulator_driver = {
 345        .driver = {
 346                .name   = "tps65090-pmic",
 347                .owner  = THIS_MODULE,
 348        },
 349        .probe          = tps65090_regulator_probe,
 350        .remove         = tps65090_regulator_remove,
 351};
 352
 353static int __init tps65090_regulator_init(void)
 354{
 355        return platform_driver_register(&tps65090_regulator_driver);
 356}
 357subsys_initcall(tps65090_regulator_init);
 358
 359static void __exit tps65090_regulator_exit(void)
 360{
 361        platform_driver_unregister(&tps65090_regulator_driver);
 362}
 363module_exit(tps65090_regulator_exit);
 364
 365MODULE_DESCRIPTION("tps65090 regulator driver");
 366MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
 367MODULE_LICENSE("GPL v2");
 368MODULE_ALIAS("platform:tps65090-pmic");
 369
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.