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 regulator_dev    *regulator;
  53        struct device           *dev;
  54        struct regmap           *regmap;
  55
  56        unsigned        mode:2; /* bit[1:0] = VID1, VID0 */
  57        unsigned        extclk_freq:2;
  58        unsigned        extclk:1;
  59        unsigned        ramp_timing:3;
  60        unsigned        ramp_down:1;
  61};
  62
  63static int max8649_enable_time(struct regulator_dev *rdev)
  64{
  65        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
  66        int voltage, rate, ret;
  67        unsigned int val;
  68
  69        /* get voltage */
  70        ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
  71        if (ret != 0)
  72                return ret;
  73        val &= MAX8649_VOL_MASK;
  74        voltage = regulator_list_voltage_linear(rdev, (unsigned char)val);
  75
  76        /* get rate */
  77        ret = regmap_read(info->regmap, MAX8649_RAMP, &val);
  78        if (ret != 0)
  79                return ret;
  80        ret = (val & MAX8649_RAMP_MASK) >> 5;
  81        rate = (32 * 1000) >> ret;      /* uV/uS */
  82
  83        return DIV_ROUND_UP(voltage, rate);
  84}
  85
  86static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
  87{
  88        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
  89
  90        switch (mode) {
  91        case REGULATOR_MODE_FAST:
  92                regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
  93                                   MAX8649_FORCE_PWM, MAX8649_FORCE_PWM);
  94                break;
  95        case REGULATOR_MODE_NORMAL:
  96                regmap_update_bits(info->regmap, rdev->desc->vsel_reg,
  97                                   MAX8649_FORCE_PWM, 0);
  98                break;
  99        default:
 100                return -EINVAL;
 101        }
 102        return 0;
 103}
 104
 105static unsigned int max8649_get_mode(struct regulator_dev *rdev)
 106{
 107        struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
 108        unsigned int val;
 109        int ret;
 110
 111        ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val);
 112        if (ret != 0)
 113                return ret;
 114        if (val & MAX8649_FORCE_PWM)
 115                return REGULATOR_MODE_FAST;
 116        return REGULATOR_MODE_NORMAL;
 117}
 118
 119static struct regulator_ops max8649_dcdc_ops = {
 120        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 121        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 122        .list_voltage   = regulator_list_voltage_linear,
 123        .map_voltage    = regulator_map_voltage_linear,
 124        .enable         = regulator_enable_regmap,
 125        .disable        = regulator_disable_regmap,
 126        .is_enabled     = regulator_is_enabled_regmap,
 127        .enable_time    = max8649_enable_time,
 128        .set_mode       = max8649_set_mode,
 129        .get_mode       = max8649_get_mode,
 130
 131};
 132
 133static struct regulator_desc dcdc_desc = {
 134        .name           = "max8649",
 135        .ops            = &max8649_dcdc_ops,
 136        .type           = REGULATOR_VOLTAGE,
 137        .n_voltages     = 1 << 6,
 138        .owner          = THIS_MODULE,
 139        .vsel_mask      = MAX8649_VOL_MASK,
 140        .min_uV         = MAX8649_DCDC_VMIN,
 141        .uV_step        = MAX8649_DCDC_STEP,
 142        .enable_reg     = MAX8649_CONTROL,
 143        .enable_mask    = MAX8649_EN_PD,
 144        .enable_is_inverted = true,
 145};
 146
 147static struct regmap_config max8649_regmap_config = {
 148        .reg_bits = 8,
 149        .val_bits = 8,
 150};
 151
 152static int max8649_regulator_probe(struct i2c_client *client,
 153                                             const struct i2c_device_id *id)
 154{
 155        struct max8649_platform_data *pdata = client->dev.platform_data;
 156        struct max8649_regulator_info *info = NULL;
 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                dev_err(&client->dev, "No enough memory\n");
 166                return -ENOMEM;
 167        }
 168
 169        info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);
 170        if (IS_ERR(info->regmap)) {
 171                ret = PTR_ERR(info->regmap);
 172                dev_err(&client->dev, "Failed to allocate register map: %d\n", ret);
 173                return ret;
 174        }
 175
 176        info->dev = &client->dev;
 177        i2c_set_clientdata(client, info);
 178
 179        info->mode = pdata->mode;
 180        switch (info->mode) {
 181        case 0:
 182                dcdc_desc.vsel_reg = MAX8649_MODE0;
 183                break;
 184        case 1:
 185                dcdc_desc.vsel_reg = MAX8649_MODE1;
 186                break;
 187        case 2:
 188                dcdc_desc.vsel_reg = MAX8649_MODE2;
 189                break;
 190        case 3:
 191                dcdc_desc.vsel_reg = MAX8649_MODE3;
 192                break;
 193        default:
 194                break;
 195        }
 196
 197        ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val);
 198        if (ret != 0) {
 199                dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
 200                        ret);
 201                return ret;
 202        }
 203        dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);
 204
 205        /* enable VID0 & VID1 */
 206        regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
 207
 208        /* enable/disable external clock synchronization */
 209        info->extclk = pdata->extclk;
 210        data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
 211        regmap_update_bits(info->regmap, dcdc_desc.vsel_reg,
 212                           MAX8649_SYNC_EXTCLK, data);
 213        if (info->extclk) {
 214                /* set external clock frequency */
 215                info->extclk_freq = pdata->extclk_freq;
 216                regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK,
 217                                   info->extclk_freq << 6);
 218        }
 219
 220        if (pdata->ramp_timing) {
 221                info->ramp_timing = pdata->ramp_timing;
 222                regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK,
 223                                   info->ramp_timing << 5);
 224        }
 225
 226        info->ramp_down = pdata->ramp_down;
 227        if (info->ramp_down) {
 228                regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN,
 229                                   MAX8649_RAMP_DOWN);
 230        }
 231
 232        config.dev = &client->dev;
 233        config.init_data = pdata->regulator;
 234        config.driver_data = info;
 235        config.regmap = info->regmap;
 236
 237        info->regulator = regulator_register(&dcdc_desc, &config);
 238        if (IS_ERR(info->regulator)) {
 239                dev_err(info->dev, "failed to register regulator %s\n",
 240                        dcdc_desc.name);
 241                return PTR_ERR(info->regulator);
 242        }
 243
 244        return 0;
 245}
 246
 247static int max8649_regulator_remove(struct i2c_client *client)
 248{
 249        struct max8649_regulator_info *info = i2c_get_clientdata(client);
 250
 251        if (info)
 252                regulator_unregister(info->regulator);
 253
 254        return 0;
 255}
 256
 257static const struct i2c_device_id max8649_id[] = {
 258        { "max8649", 0 },
 259        { }
 260};
 261MODULE_DEVICE_TABLE(i2c, max8649_id);
 262
 263static struct i2c_driver max8649_driver = {
 264        .probe          = max8649_regulator_probe,
 265        .remove         = max8649_regulator_remove,
 266        .driver         = {
 267                .name   = "max8649",
 268        },
 269        .id_table       = max8649_id,
 270};
 271
 272static int __init max8649_init(void)
 273{
 274        return i2c_add_driver(&max8649_driver);
 275}
 276subsys_initcall(max8649_init);
 277
 278static void __exit max8649_exit(void)
 279{
 280        i2c_del_driver(&max8649_driver);
 281}
 282module_exit(max8649_exit);
 283
 284/* Module information */
 285MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
 286MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 287MODULE_LICENSE("GPL");
 288
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.