linux/drivers/regulator/max8925-regulator.c
<<
>>
Prefs
   1/*
   2 * Regulators driver for Maxim max8925
   3 *
   4 * Copyright (C) 2009 Marvell International Ltd.
   5 *      Haojian Zhuang <haojian.zhuang@marvell.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/err.h>
  15#include <linux/i2c.h>
  16#include <linux/platform_device.h>
  17#include <linux/regulator/driver.h>
  18#include <linux/regulator/machine.h>
  19#include <linux/mfd/max8925.h>
  20#include <linux/of.h>
  21#include <linux/regulator/of_regulator.h>
  22
  23#define SD1_DVM_VMIN            850000
  24#define SD1_DVM_VMAX            1000000
  25#define SD1_DVM_STEP            50000
  26#define SD1_DVM_SHIFT           5               /* SDCTL1 bit5 */
  27#define SD1_DVM_EN              6               /* SDV1 bit 6 */
  28
  29/* bit definitions in LDO control registers */
  30#define LDO_SEQ_I2C             0x7             /* Power U/D by i2c */
  31#define LDO_SEQ_MASK            0x7             /* Power U/D sequence mask */
  32#define LDO_SEQ_SHIFT           2               /* Power U/D sequence offset */
  33#define LDO_I2C_EN              0x1             /* Enable by i2c */
  34#define LDO_I2C_EN_MASK         0x1             /* Enable mask by i2c */
  35#define LDO_I2C_EN_SHIFT        0               /* Enable offset by i2c */
  36
  37struct max8925_regulator_info {
  38        struct regulator_desc   desc;
  39        struct i2c_client       *i2c;
  40
  41        int     vol_reg;
  42        int     enable_reg;
  43};
  44
  45static int max8925_set_voltage_sel(struct regulator_dev *rdev,
  46                                   unsigned int selector)
  47{
  48        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
  49        unsigned char mask = rdev->desc->n_voltages - 1;
  50
  51        return max8925_set_bits(info->i2c, info->vol_reg, mask, selector);
  52}
  53
  54static int max8925_get_voltage_sel(struct regulator_dev *rdev)
  55{
  56        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
  57        unsigned char data, mask;
  58        int ret;
  59
  60        ret = max8925_reg_read(info->i2c, info->vol_reg);
  61        if (ret < 0)
  62                return ret;
  63        mask = rdev->desc->n_voltages - 1;
  64        data = ret & mask;
  65
  66        return data;
  67}
  68
  69static int max8925_enable(struct regulator_dev *rdev)
  70{
  71        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
  72
  73        return max8925_set_bits(info->i2c, info->enable_reg,
  74                                LDO_SEQ_MASK << LDO_SEQ_SHIFT |
  75                                LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,
  76                                LDO_SEQ_I2C << LDO_SEQ_SHIFT |
  77                                LDO_I2C_EN << LDO_I2C_EN_SHIFT);
  78}
  79
  80static int max8925_disable(struct regulator_dev *rdev)
  81{
  82        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
  83
  84        return max8925_set_bits(info->i2c, info->enable_reg,
  85                                LDO_SEQ_MASK << LDO_SEQ_SHIFT |
  86                                LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,
  87                                LDO_SEQ_I2C << LDO_SEQ_SHIFT);
  88}
  89
  90static int max8925_is_enabled(struct regulator_dev *rdev)
  91{
  92        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
  93        int ldo_seq, ret;
  94
  95        ret = max8925_reg_read(info->i2c, info->enable_reg);
  96        if (ret < 0)
  97                return ret;
  98        ldo_seq = (ret >> LDO_SEQ_SHIFT) & LDO_SEQ_MASK;
  99        if (ldo_seq != LDO_SEQ_I2C)
 100                return 1;
 101        else
 102                return ret & (LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT);
 103}
 104
 105static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV)
 106{
 107        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 108        unsigned char data, mask;
 109
 110        if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX)
 111                return -EINVAL;
 112
 113        data = DIV_ROUND_UP(uV - SD1_DVM_VMIN, SD1_DVM_STEP);
 114        data <<= SD1_DVM_SHIFT;
 115        mask = 3 << SD1_DVM_SHIFT;
 116
 117        return max8925_set_bits(info->i2c, info->enable_reg, mask, data);
 118}
 119
 120static int max8925_set_dvm_enable(struct regulator_dev *rdev)
 121{
 122        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 123
 124        return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN,
 125                                1 << SD1_DVM_EN);
 126}
 127
 128static int max8925_set_dvm_disable(struct regulator_dev *rdev)
 129{
 130        struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 131
 132        return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0);
 133}
 134
 135static const struct regulator_ops max8925_regulator_sdv_ops = {
 136        .map_voltage            = regulator_map_voltage_linear,
 137        .list_voltage           = regulator_list_voltage_linear,
 138        .set_voltage_sel        = max8925_set_voltage_sel,
 139        .get_voltage_sel        = max8925_get_voltage_sel,
 140        .enable                 = max8925_enable,
 141        .disable                = max8925_disable,
 142        .is_enabled             = max8925_is_enabled,
 143        .set_suspend_voltage    = max8925_set_dvm_voltage,
 144        .set_suspend_enable     = max8925_set_dvm_enable,
 145        .set_suspend_disable    = max8925_set_dvm_disable,
 146};
 147
 148static const struct regulator_ops max8925_regulator_ldo_ops = {
 149        .map_voltage            = regulator_map_voltage_linear,
 150        .list_voltage           = regulator_list_voltage_linear,
 151        .set_voltage_sel        = max8925_set_voltage_sel,
 152        .get_voltage_sel        = max8925_get_voltage_sel,
 153        .enable                 = max8925_enable,
 154        .disable                = max8925_disable,
 155        .is_enabled             = max8925_is_enabled,
 156};
 157
 158#define MAX8925_SDV(_id, min, max, step)                        \
 159{                                                               \
 160        .desc   = {                                             \
 161                .name   = "SDV" #_id,                           \
 162                .ops    = &max8925_regulator_sdv_ops,           \
 163                .type   = REGULATOR_VOLTAGE,                    \
 164                .id     = MAX8925_ID_SD##_id,                   \
 165                .owner  = THIS_MODULE,                          \
 166                .n_voltages = 64,                               \
 167                .min_uV = min * 1000,                           \
 168                .uV_step = step * 1000,                         \
 169        },                                                      \
 170        .vol_reg        = MAX8925_SDV##_id,                     \
 171        .enable_reg     = MAX8925_SDCTL##_id,                   \
 172}
 173
 174#define MAX8925_LDO(_id, min, max, step)                        \
 175{                                                               \
 176        .desc   = {                                             \
 177                .name   = "LDO" #_id,                           \
 178                .ops    = &max8925_regulator_ldo_ops,           \
 179                .type   = REGULATOR_VOLTAGE,                    \
 180                .id     = MAX8925_ID_LDO##_id,                  \
 181                .owner  = THIS_MODULE,                          \
 182                .n_voltages = 64,                               \
 183                .min_uV = min * 1000,                           \
 184                .uV_step = step * 1000,                         \
 185        },                                                      \
 186        .vol_reg        = MAX8925_LDOVOUT##_id,                 \
 187        .enable_reg     = MAX8925_LDOCTL##_id,                  \
 188}
 189
 190#ifdef CONFIG_OF
 191static struct of_regulator_match max8925_regulator_matches[] = {
 192        { .name = "SDV1",},
 193        { .name = "SDV2",},
 194        { .name = "SDV3",},
 195        { .name = "LDO1",},
 196        { .name = "LDO2",},
 197        { .name = "LDO3",},
 198        { .name = "LDO4",},
 199        { .name = "LDO5",},
 200        { .name = "LDO6",},
 201        { .name = "LDO7",},
 202        { .name = "LDO8",},
 203        { .name = "LDO9",},
 204        { .name = "LDO10",},
 205        { .name = "LDO11",},
 206        { .name = "LDO12",},
 207        { .name = "LDO13",},
 208        { .name = "LDO14",},
 209        { .name = "LDO15",},
 210        { .name = "LDO16",},
 211        { .name = "LDO17",},
 212        { .name = "LDO18",},
 213        { .name = "LDO19",},
 214        { .name = "LDO20",},
 215};
 216#endif
 217
 218static struct max8925_regulator_info max8925_regulator_info[] = {
 219        MAX8925_SDV(1, 637.5, 1425, 12.5),
 220        MAX8925_SDV(2,   650, 2225,   25),
 221        MAX8925_SDV(3,   750, 3900,   50),
 222
 223        MAX8925_LDO(1,  750, 3900, 50),
 224        MAX8925_LDO(2,  650, 2250, 25),
 225        MAX8925_LDO(3,  650, 2250, 25),
 226        MAX8925_LDO(4,  750, 3900, 50),
 227        MAX8925_LDO(5,  750, 3900, 50),
 228        MAX8925_LDO(6,  750, 3900, 50),
 229        MAX8925_LDO(7,  750, 3900, 50),
 230        MAX8925_LDO(8,  750, 3900, 50),
 231        MAX8925_LDO(9,  750, 3900, 50),
 232        MAX8925_LDO(10, 750, 3900, 50),
 233        MAX8925_LDO(11, 750, 3900, 50),
 234        MAX8925_LDO(12, 750, 3900, 50),
 235        MAX8925_LDO(13, 750, 3900, 50),
 236        MAX8925_LDO(14, 750, 3900, 50),
 237        MAX8925_LDO(15, 750, 3900, 50),
 238        MAX8925_LDO(16, 750, 3900, 50),
 239        MAX8925_LDO(17, 650, 2250, 25),
 240        MAX8925_LDO(18, 650, 2250, 25),
 241        MAX8925_LDO(19, 750, 3900, 50),
 242        MAX8925_LDO(20, 750, 3900, 50),
 243};
 244
 245#ifdef CONFIG_OF
 246static int max8925_regulator_dt_init(struct platform_device *pdev,
 247                                    struct regulator_config *config,
 248                                    int ridx)
 249{
 250        struct device_node *nproot, *np;
 251        int rcount;
 252
 253        nproot = pdev->dev.parent->of_node;
 254        if (!nproot)
 255                return -ENODEV;
 256        np = of_get_child_by_name(nproot, "regulators");
 257        if (!np) {
 258                dev_err(&pdev->dev, "failed to find regulators node\n");
 259                return -ENODEV;
 260        }
 261
 262        rcount = of_regulator_match(&pdev->dev, np,
 263                                &max8925_regulator_matches[ridx], 1);
 264        of_node_put(np);
 265        if (rcount < 0)
 266                return rcount;
 267        config->init_data =     max8925_regulator_matches[ridx].init_data;
 268        config->of_node = max8925_regulator_matches[ridx].of_node;
 269
 270        return 0;
 271}
 272#else
 273#define max8925_regulator_dt_init(x, y, z)      (-1)
 274#endif
 275
 276static int max8925_regulator_probe(struct platform_device *pdev)
 277{
 278        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 279        struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
 280        struct regulator_config config = { };
 281        struct max8925_regulator_info *ri;
 282        struct resource *res;
 283        struct regulator_dev *rdev;
 284        int i, regulator_idx;
 285
 286        res = platform_get_resource(pdev, IORESOURCE_REG, 0);
 287        if (!res) {
 288                dev_err(&pdev->dev, "No REG resource!\n");
 289                return -EINVAL;
 290        }
 291        for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
 292                ri = &max8925_regulator_info[i];
 293                if (ri->vol_reg == res->start) {
 294                        regulator_idx = i;
 295                        break;
 296                }
 297        }
 298
 299        if (i == ARRAY_SIZE(max8925_regulator_info)) {
 300                dev_err(&pdev->dev, "Failed to find regulator %llu\n",
 301                        (unsigned long long)res->start);
 302                return -EINVAL;
 303        }
 304        ri->i2c = chip->i2c;
 305
 306        config.dev = &pdev->dev;
 307        config.driver_data = ri;
 308
 309        if (max8925_regulator_dt_init(pdev, &config, regulator_idx))
 310                if (pdata)
 311                        config.init_data = pdata;
 312
 313        rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
 314        if (IS_ERR(rdev)) {
 315                dev_err(&pdev->dev, "failed to register regulator %s\n",
 316                                ri->desc.name);
 317                return PTR_ERR(rdev);
 318        }
 319
 320        platform_set_drvdata(pdev, rdev);
 321        return 0;
 322}
 323
 324static struct platform_driver max8925_regulator_driver = {
 325        .driver         = {
 326                .name   = "max8925-regulator",
 327        },
 328        .probe          = max8925_regulator_probe,
 329};
 330
 331static int __init max8925_regulator_init(void)
 332{
 333        return platform_driver_register(&max8925_regulator_driver);
 334}
 335subsys_initcall(max8925_regulator_init);
 336
 337static void __exit max8925_regulator_exit(void)
 338{
 339        platform_driver_unregister(&max8925_regulator_driver);
 340}
 341module_exit(max8925_regulator_exit);
 342
 343MODULE_LICENSE("GPL");
 344MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 345MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");
 346MODULE_ALIAS("platform:max8925-regulator");
 347