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
  21#define SD1_DVM_VMIN            850000
  22#define SD1_DVM_VMAX            1000000
  23#define SD1_DVM_STEP            50000
  24#define SD1_DVM_SHIFT           5               /* SDCTL1 bit5 */
  25#define SD1_DVM_EN              6               /* SDV1 bit 6 */
  26
  27/* bit definitions in LDO control registers */
  28#define LDO_SEQ_I2C             0x7             /* Power U/D by i2c */
  29#define LDO_SEQ_MASK            0x7             /* Power U/D sequence mask */
  30#define LDO_SEQ_SHIFT           2               /* Power U/D sequence offset */
  31#define LDO_I2C_EN              0x1             /* Enable by i2c */
  32#define LDO_I2C_EN_MASK         0x1             /* Enable mask by i2c */
  33#define LDO_I2C_EN_SHIFT        0               /* Enable offset by i2c */
  34
  35struct max8925_regulator_info {
  36        struct regulator_desc   desc;
  37        struct regulator_dev    *regulator;
  38        struct i2c_client       *i2c;
  39        struct max8925_chip     *chip;
  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 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 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
 190static struct max8925_regulator_info max8925_regulator_info[] = {
 191        MAX8925_SDV(1, 637.5, 1425, 12.5),
 192        MAX8925_SDV(2,   650, 2225,   25),
 193        MAX8925_SDV(3,   750, 3900,   50),
 194
 195        MAX8925_LDO(1,  750, 3900, 50),
 196        MAX8925_LDO(2,  650, 2250, 25),
 197        MAX8925_LDO(3,  650, 2250, 25),
 198        MAX8925_LDO(4,  750, 3900, 50),
 199        MAX8925_LDO(5,  750, 3900, 50),
 200        MAX8925_LDO(6,  750, 3900, 50),
 201        MAX8925_LDO(7,  750, 3900, 50),
 202        MAX8925_LDO(8,  750, 3900, 50),
 203        MAX8925_LDO(9,  750, 3900, 50),
 204        MAX8925_LDO(10, 750, 3900, 50),
 205        MAX8925_LDO(11, 750, 3900, 50),
 206        MAX8925_LDO(12, 750, 3900, 50),
 207        MAX8925_LDO(13, 750, 3900, 50),
 208        MAX8925_LDO(14, 750, 3900, 50),
 209        MAX8925_LDO(15, 750, 3900, 50),
 210        MAX8925_LDO(16, 750, 3900, 50),
 211        MAX8925_LDO(17, 650, 2250, 25),
 212        MAX8925_LDO(18, 650, 2250, 25),
 213        MAX8925_LDO(19, 750, 3900, 50),
 214        MAX8925_LDO(20, 750, 3900, 50),
 215};
 216
 217static int __devinit max8925_regulator_probe(struct platform_device *pdev)
 218{
 219        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 220        struct regulator_init_data *pdata = pdev->dev.platform_data;
 221        struct regulator_config config = { };
 222        struct max8925_regulator_info *ri;
 223        struct resource *res;
 224        struct regulator_dev *rdev;
 225        int i;
 226
 227        res = platform_get_resource(pdev, IORESOURCE_REG, 0);
 228        if (!res) {
 229                dev_err(&pdev->dev, "No REG resource!\n");
 230                return -EINVAL;
 231        }
 232        for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
 233                ri = &max8925_regulator_info[i];
 234                if (ri->vol_reg == res->start)
 235                        break;
 236        }
 237        if (i == ARRAY_SIZE(max8925_regulator_info)) {
 238                dev_err(&pdev->dev, "Failed to find regulator %llu\n",
 239                        (unsigned long long)res->start);
 240                return -EINVAL;
 241        }
 242        ri->i2c = chip->i2c;
 243        ri->chip = chip;
 244
 245        config.dev = &pdev->dev;
 246        config.init_data = pdata;
 247        config.driver_data = ri;
 248
 249        rdev = regulator_register(&ri->desc, &config);
 250        if (IS_ERR(rdev)) {
 251                dev_err(&pdev->dev, "failed to register regulator %s\n",
 252                                ri->desc.name);
 253                return PTR_ERR(rdev);
 254        }
 255
 256        platform_set_drvdata(pdev, rdev);
 257        return 0;
 258}
 259
 260static int __devexit max8925_regulator_remove(struct platform_device *pdev)
 261{
 262        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 263
 264        platform_set_drvdata(pdev, NULL);
 265        regulator_unregister(rdev);
 266
 267        return 0;
 268}
 269
 270static struct platform_driver max8925_regulator_driver = {
 271        .driver         = {
 272                .name   = "max8925-regulator",
 273                .owner  = THIS_MODULE,
 274        },
 275        .probe          = max8925_regulator_probe,
 276        .remove         = __devexit_p(max8925_regulator_remove),
 277};
 278
 279static int __init max8925_regulator_init(void)
 280{
 281        return platform_driver_register(&max8925_regulator_driver);
 282}
 283subsys_initcall(max8925_regulator_init);
 284
 285static void __exit max8925_regulator_exit(void)
 286{
 287        platform_driver_unregister(&max8925_regulator_driver);
 288}
 289module_exit(max8925_regulator_exit);
 290
 291MODULE_LICENSE("GPL");
 292MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 293MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");
 294MODULE_ALIAS("platform:max8925-regulator");
 295
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.