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/slab.h>
  23#include <linux/err.h>
  24#include <linux/platform_device.h>
  25#include <linux/regulator/driver.h>
  26#include <linux/regulator/machine.h>
  27#include <linux/mfd/tps65090.h>
  28
  29struct tps65090_regulator {
  30        struct device           *dev;
  31        struct regulator_desc   *desc;
  32        struct regulator_dev    *rdev;
  33};
  34
  35static struct regulator_ops tps65090_ext_control_ops = {
  36};
  37
  38static struct regulator_ops tps65090_reg_contol_ops = {
  39        .enable         = regulator_enable_regmap,
  40        .disable        = regulator_disable_regmap,
  41        .is_enabled     = regulator_is_enabled_regmap,
  42};
  43
  44static struct regulator_ops tps65090_ldo_ops = {
  45};
  46
  47#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)   \
  48{                                                       \
  49        .name = "TPS65090_RAILS"#_id,                   \
  50        .supply_name = _sname,                          \
  51        .id = TPS65090_REGULATOR_##_id,                 \
  52        .ops = &_ops,                                   \
  53        .enable_reg = _en_reg,                          \
  54        .enable_mask = BIT(0),                          \
  55        .type = REGULATOR_VOLTAGE,                      \
  56        .owner = THIS_MODULE,                           \
  57}
  58
  59static struct regulator_desc tps65090_regulator_desc[] = {
  60        tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_reg_contol_ops),
  61        tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_reg_contol_ops),
  62        tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_reg_contol_ops),
  63        tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_reg_contol_ops),
  64        tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_reg_contol_ops),
  65        tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_reg_contol_ops),
  66        tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_reg_contol_ops),
  67        tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
  68        tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
  69        tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
  70        tps65090_REG_DESC(LDO1,  "vsys_l1", 0,    tps65090_ldo_ops),
  71        tps65090_REG_DESC(LDO2,  "vsys_l2", 0,    tps65090_ldo_ops),
  72};
  73
  74static inline bool is_dcdc(int id)
  75{
  76        switch (id) {
  77        case TPS65090_REGULATOR_DCDC1:
  78        case TPS65090_REGULATOR_DCDC2:
  79        case TPS65090_REGULATOR_DCDC3:
  80                return true;
  81        default:
  82                return false;
  83        }
  84}
  85
  86static int tps65090_config_ext_control(
  87        struct tps65090_regulator *ri, bool enable)
  88{
  89        int ret;
  90        struct device *parent = ri->dev->parent;
  91        unsigned int reg_en_reg = ri->desc->enable_reg;
  92
  93        if (enable)
  94                ret = tps65090_set_bits(parent, reg_en_reg, 1);
  95        else
  96                ret =  tps65090_clr_bits(parent, reg_en_reg, 1);
  97        if (ret < 0)
  98                dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg);
  99        return ret;
 100}
 101
 102static int tps65090_regulator_disable_ext_control(
 103                struct tps65090_regulator *ri,
 104                struct tps65090_regulator_plat_data *tps_pdata)
 105{
 106        int ret = 0;
 107        struct device *parent = ri->dev->parent;
 108        unsigned int reg_en_reg = ri->desc->enable_reg;
 109
 110        /*
 111         * First enable output for internal control if require.
 112         * And then disable external control.
 113         */
 114        if (tps_pdata->reg_init_data->constraints.always_on ||
 115                        tps_pdata->reg_init_data->constraints.boot_on) {
 116                ret =  tps65090_set_bits(parent, reg_en_reg, 0);
 117                if (ret < 0) {
 118                        dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg);
 119                        return ret;
 120                }
 121        }
 122        return tps65090_config_ext_control(ri, false);
 123}
 124
 125static void tps65090_configure_regulator_config(
 126                struct tps65090_regulator_plat_data *tps_pdata,
 127                struct regulator_config *config)
 128{
 129        if (gpio_is_valid(tps_pdata->gpio)) {
 130                int gpio_flag = GPIOF_OUT_INIT_LOW;
 131
 132                if (tps_pdata->reg_init_data->constraints.always_on ||
 133                                tps_pdata->reg_init_data->constraints.boot_on)
 134                        gpio_flag = GPIOF_OUT_INIT_HIGH;
 135
 136                config->ena_gpio = tps_pdata->gpio;
 137                config->ena_gpio_flags = gpio_flag;
 138        }
 139}
 140
 141static int tps65090_regulator_probe(struct platform_device *pdev)
 142{
 143        struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
 144        struct tps65090_regulator *ri = NULL;
 145        struct regulator_config config = { };
 146        struct regulator_dev *rdev;
 147        struct tps65090_regulator_plat_data *tps_pdata;
 148        struct tps65090_regulator *pmic;
 149        struct tps65090_platform_data *tps65090_pdata;
 150        int num;
 151        int ret;
 152
 153        dev_dbg(&pdev->dev, "Probing regulator\n");
 154
 155        tps65090_pdata = dev_get_platdata(pdev->dev.parent);
 156        if (!tps65090_pdata) {
 157                dev_err(&pdev->dev, "Platform data missing\n");
 158                return -EINVAL;
 159        }
 160
 161        pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
 162                        GFP_KERNEL);
 163        if (!pmic) {
 164                dev_err(&pdev->dev, "mem alloc for pmic failed\n");
 165                return -ENOMEM;
 166        }
 167
 168        for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
 169                tps_pdata = tps65090_pdata->reg_pdata[num];
 170
 171                ri = &pmic[num];
 172                ri->dev = &pdev->dev;
 173                ri->desc = &tps65090_regulator_desc[num];
 174
 175                /*
 176                 * TPS5090 DCDC support the control from external digital input.
 177                 * Configure it as per platform data.
 178                 */
 179                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) {
 180                        if (tps_pdata->enable_ext_control) {
 181                                tps65090_configure_regulator_config(
 182                                                tps_pdata, &config);
 183                                ri->desc->ops = &tps65090_ext_control_ops;
 184                        } else {
 185                                ret = tps65090_regulator_disable_ext_control(
 186                                                ri, tps_pdata);
 187                                if (ret < 0) {
 188                                        dev_err(&pdev->dev,
 189                                                "failed disable ext control\n");
 190                                        goto scrub;
 191                                }
 192                        }
 193                }
 194
 195                config.dev = &pdev->dev;
 196                config.driver_data = ri;
 197                config.regmap = tps65090_mfd->rmap;
 198                if (tps_pdata)
 199                        config.init_data = tps_pdata->reg_init_data;
 200                else
 201                        config.init_data = NULL;
 202
 203                rdev = regulator_register(ri->desc, &config);
 204                if (IS_ERR(rdev)) {
 205                        dev_err(&pdev->dev, "failed to register regulator %s\n",
 206                                ri->desc->name);
 207                        ret = PTR_ERR(rdev);
 208                        goto scrub;
 209                }
 210                ri->rdev = rdev;
 211
 212                /* Enable external control if it is require */
 213                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&
 214                                tps_pdata->enable_ext_control) {
 215                        ret = tps65090_config_ext_control(ri, true);
 216                        if (ret < 0) {
 217                                /* Increment num to get unregister rdev */
 218                                num++;
 219                                goto scrub;
 220                        }
 221                }
 222        }
 223
 224        platform_set_drvdata(pdev, pmic);
 225        return 0;
 226
 227scrub:
 228        while (--num >= 0) {
 229                ri = &pmic[num];
 230                regulator_unregister(ri->rdev);
 231        }
 232        return ret;
 233}
 234
 235static int tps65090_regulator_remove(struct platform_device *pdev)
 236{
 237        struct tps65090_regulator *pmic = platform_get_drvdata(pdev);
 238        struct tps65090_regulator *ri;
 239        int num;
 240
 241        for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) {
 242                ri = &pmic[num];
 243                regulator_unregister(ri->rdev);
 244        }
 245        return 0;
 246}
 247
 248static struct platform_driver tps65090_regulator_driver = {
 249        .driver = {
 250                .name   = "tps65090-pmic",
 251                .owner  = THIS_MODULE,
 252        },
 253        .probe          = tps65090_regulator_probe,
 254        .remove         = tps65090_regulator_remove,
 255};
 256
 257static int __init tps65090_regulator_init(void)
 258{
 259        return platform_driver_register(&tps65090_regulator_driver);
 260}
 261subsys_initcall(tps65090_regulator_init);
 262
 263static void __exit tps65090_regulator_exit(void)
 264{
 265        platform_driver_unregister(&tps65090_regulator_driver);
 266}
 267module_exit(tps65090_regulator_exit);
 268
 269MODULE_DESCRIPTION("tps65090 regulator driver");
 270MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
 271MODULE_LICENSE("GPL v2");
 272MODULE_ALIAS("platform:tps65090-pmic");
 273
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.