linux/drivers/regulator/max8649.c
<<
>>
Prefs
   1/*
   2 * Regulators driver for Maxim max8649
   3 *
   4 * Copyright (C) 2009-2010 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/err.h>
  14#include <linux/i2c.h>
  15#include <linux/platform_device.h>
  16#include <linux/regulator/driver.h>
  17#include <linux/slab.h>
  18#include <linux/regulator/max8649.h>
  19#include <linux/regmap.h>
  20
  21#define MAX8649_DCDC_VMIN       750000          /* uV */
  22#define MAX8649_DCDC_VMAX       1380000         /* uV */
  23#define MAX8649_DCDC_STEP       10000           /* uV */
  24#define MAX8649_VOL_MASK        0x3f
  25
  26/* Registers */
  27#define MAX8649_MODE0           0x00
  28#define MAX8649_MODE1           0x01
  29#define MAX8649_MODE2           0x02
  30#define MAX8649_MODE3           0x03
  31#define MAX8649_CONTROL         0x04
  32#define MAX8649_SYNC            0x05
  33#define MAX8649_RAMP            0x06
  34#define MAX8649_CHIP_ID1        0x08
  35#define MAX8649_CHIP_ID2        0x09
  36
  37/* Bits */
  38#define MAX8649_EN_PD           (1 << 7)
  39#define MAX8649_VID0_PD         (1 << 6)
  40#define MAX8649_VID1_PD         (1 << 5)
  41#define MAX8649_VID_MASK        (3 << 5)
  42
  43#define MAX8649_FORCE_PWM       (1 << 7)
  44#define MAX8649_SYNC_EXTCLK     (1 << 6)
  45
  46#define MAX8649_EXT_MASK        (3 << 6)
  47
  48#define MAX8649_RAMP_MASK       (7 << 5)
  49#define MAX8649_RAMP_DOWN       (1 << 1)
  50
  51struct max8649_regulator_info {
  52        struct device           *dev;
  53        struct regmap           *regmap;
  54
  55        unsigned        mode:2; /* bit[1:0] = VID1, VID0 */
  56        unsigned        extclk_freq:2;
  57        unsigned        extclk:1;
  58        unsigned        ramp_timing:3;
  59        unsigned        ramp_down:1;
  60};
  61
  62static int max8649_enable_time(struct regulator_dev *rdev)
  63{
  64        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
  65        int voltage, rate, ret;
  66        unsigned int val;
  67
  68        /* get voltage */
  69        ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
  70        if (ret != 0)
  71                return ret;
  72        val &= MAX8649_VOL_MASK;
  73        voltage = regulator_list_voltage_linear(rdev, (unsigned char)val);
  74
  75        /* get rate */
  76        ret = regmap_read(info->regmap, MAX8649_RAMP, &val);
  77        if (ret != 0)
  78                return ret;
  79        ret = (val & MAX8649_RAMP_MASK) >> 5;
  80        rate = (32 * 1000) >> ret;      /* uV/uS */
  81
  82        return DIV_ROUND_UP(voltage, rate);
  83}
  84
  85static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
  86{
  87        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
  88
  89        switch (mode) {
  90        case REGULATOR_MODE_FAST:
  91                regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
  92                                   MAX8649_FORCE_PWM, MAX8649_FORCE_PWM);
  93                break;
  94        case REGULATOR_MODE_NORMAL:
  95                regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
  96                                   MAX8649_FORCE_PWM, 0);
  97                break;
  98        default:
  99                return -EINVAL;
 100        }
 101        return 0;
 102}
 103
 104static unsigned int max8649_get_mode(struct regulator_dev *rdev)
 105{
 106        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
 107        unsigned int val;
 108        int ret;
 109
 110        ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
 111        if (ret != 0)
 112                return ret;
 113        if (val & MAX8649_FORCE_PWM)
 114                return REGULATOR_MODE_FAST;
 115        return REGULATOR_MODE_NORMAL;
 116}
 117
 118static const struct regulator_ops max8649_dcdc_ops = {
 119        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 120        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 121        .list_voltage   = regulator_list_voltage_linear,
 122        .map_voltage    = regulator_map_voltage_linear,
 123        .enable         = regulator_enable_regmap,
 124        .disable        = regulator_disable_regmap,
 125        .is_enabled     = regulator_is_enabled_regmap,
 126        .enable_time    = max8649_enable_time,
 127        .set_mode       = max8649_set_mode,
 128        .get_mode       = max8649_get_mode,
 129
 130};
 131
 132static struct regulator_desc dcdc_desc = {
 133        .name           = "max8649",
 134        .ops            = &max8649_dcdc_ops,
 135        .type           = REGULATOR_VOLTAGE,
 136        .n_voltages     = 1 << 6,
 137        .owner          = THIS_MODULE,
 138        .vsel_mask      = MAX8649_VOL_MASK,
 139        .min_uV         = MAX8649_DCDC_VMIN,
 140        .uV_step        = MAX8649_DCDC_STEP,
 141        .enable_reg     = MAX8649_CONTROL,
 142        .enable_mask    = MAX8649_EN_PD,
 143        .enable_is_inverted = true,
 144};
 145
 146static const struct regmap_config max8649_regmap_config = {
 147        .reg_bits = 8,
 148        .val_bits = 8,
 149};
 150
 151static int max8649_regulator_probe(struct i2c_client *client,
 152                                             const struct i2c_device_id *id)
 153{
 154        struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
 155        struct max8649_regulator_info *info = NULL;
 156        struct regulator_dev *regulator;
 157        struct regulator_config config = { };
 158        unsigned int val;
 159        unsigned char data;
 160        int ret;
 161
 162        info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info),
 163                            GFP_KERNEL);
 164        if (!info)
 165                return -ENOMEM;
 166
 167        info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);
 168        if (IS_ERR(info->regmap)) {
 169                ret = PTR_ERR(info->regmap);
 170                dev_err(&client->dev, "Failed to allocate register map: %d\n", ret);
 171                return ret;
 172        }
 173
 174        info->dev = &client->dev;
 175        i2c_set_clientdata(client, info);
 176
 177        info->mode = pdata->mode;
 178        switch (info->mode) {
 179        case 0:
 180                dcdc_desc.vsel_reg = MAX8649_MODE0;
 181                break;
 182        case 1:
 183                dcdc_desc.vsel_reg = MAX8649_MODE1;
 184                break;
 185        case 2:
 186                dcdc_desc.vsel_reg = MAX8649_MODE2;
 187                break;
 188        case 3:
 189                dcdc_desc.vsel_reg = MAX8649_MODE3;
 190                break;
 191        default:
 192                break;
 193        }
 194
 195        ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val);
 196        if (ret != 0) {
 197                dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
 198                        ret);
 199                return ret;
 200        }
 201        dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);
 202
 203        /* enable VID0 & VID1 */
 204        regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
 205
 206        /* enable/disable external clock synchronization */
 207        info->extclk = pdata->extclk;
 208        data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
 209        regmap_update_bits(info->regmap, dcdc_desc.vsel_reg,
 210                           MAX8649_SYNC_EXTCLK, data);
 211        if (info->extclk) {
 212                /* set external clock frequency */
 213                info->extclk_freq = pdata->extclk_freq;
 214                regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK,
 215                                   info->extclk_freq << 6);
 216        }
 217
 218        if (pdata->ramp_timing) {
 219                info->ramp_timing = pdata->ramp_timing;
 220                regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK,
 221                                   info->ramp_timing << 5);
 222        }
 223
 224        info->ramp_down = pdata->ramp_down;
 225        if (info->ramp_down) {
 226                regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN,
 227                                   MAX8649_RAMP_DOWN);
 228        }
 229
 230        config.dev = &client->dev;
 231        config.init_data = pdata->regulator;
 232        config.driver_data = info;
 233        config.regmap = info->regmap;
 234
 235        regulator = devm_regulator_register(&client->dev, &dcdc_desc,
 236                                                  &config);
 237        if (IS_ERR(regulator)) {
 238                dev_err(info->dev, "failed to register regulator %s\n",
 239                        dcdc_desc.name);
 240                return PTR_ERR(regulator);
 241        }
 242
 243        return 0;
 244}
 245
 246static const struct i2c_device_id max8649_id[] = {
 247        { "max8649", 0 },
 248        { }
 249};
 250MODULE_DEVICE_TABLE(i2c, max8649_id);
 251
 252static struct i2c_driver max8649_driver = {
 253        .probe          = max8649_regulator_probe,
 254        .driver         = {
 255                .name   = "max8649",
 256        },
 257        .id_table       = max8649_id,
 258};
 259
 260static int __init max8649_init(void)
 261{
 262        return i2c_add_driver(&max8649_driver);
 263}
 264subsys_initcall(max8649_init);
 265
 266static void __exit max8649_exit(void)
 267{
 268        i2c_del_driver(&max8649_driver);
 269}
 270module_exit(max8649_exit);
 271
 272/* Module information */
 273MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
 274MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 275MODULE_LICENSE("GPL");
 276