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