linux/drivers/regulator/pcf50633-regulator.c
<<
>>
Prefs
   1/* NXP PCF50633 PMIC Driver
   2 *
   3 * (C) 2006-2008 by Openmoko, Inc.
   4 * Author: Balaji Rao <balajirrao@openmoko.org>
   5 * All rights reserved.
   6 *
   7 * Broken down from monstrous PCF50633 driver mainly by
   8 * Harald Welte and Andy Green and Werner Almesberger
   9 *
  10 *  This program is free software; you can redistribute  it and/or modify it
  11 *  under  the terms of  the GNU General  Public License as published by the
  12 *  Free Software Foundation;  either version 2 of the  License, or (at your
  13 *  option) any later version.
  14 *
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/init.h>
  20#include <linux/device.h>
  21#include <linux/err.h>
  22#include <linux/platform_device.h>
  23
  24#include <linux/mfd/pcf50633/core.h>
  25#include <linux/mfd/pcf50633/pmic.h>
  26
  27#define PCF50633_REGULATOR(_name, _id)          \
  28        {                                       \
  29                .name = _name,                  \
  30                .id = _id,                      \
  31                .ops = &pcf50633_regulator_ops, \
  32                .type = REGULATOR_VOLTAGE,      \
  33                .owner = THIS_MODULE,           \
  34        }
  35
  36static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
  37        [PCF50633_REGULATOR_AUTO]       = PCF50633_REG_AUTOOUT,
  38        [PCF50633_REGULATOR_DOWN1]      = PCF50633_REG_DOWN1OUT,
  39        [PCF50633_REGULATOR_DOWN2]      = PCF50633_REG_DOWN2OUT,
  40        [PCF50633_REGULATOR_MEMLDO]     = PCF50633_REG_MEMLDOOUT,
  41        [PCF50633_REGULATOR_LDO1]       = PCF50633_REG_LDO1OUT,
  42        [PCF50633_REGULATOR_LDO2]       = PCF50633_REG_LDO2OUT,
  43        [PCF50633_REGULATOR_LDO3]       = PCF50633_REG_LDO3OUT,
  44        [PCF50633_REGULATOR_LDO4]       = PCF50633_REG_LDO4OUT,
  45        [PCF50633_REGULATOR_LDO5]       = PCF50633_REG_LDO5OUT,
  46        [PCF50633_REGULATOR_LDO6]       = PCF50633_REG_LDO6OUT,
  47        [PCF50633_REGULATOR_HCLDO]      = PCF50633_REG_HCLDOOUT,
  48};
  49
  50/* Bits from voltage value */
  51static u8 auto_voltage_bits(unsigned int millivolts)
  52{
  53        if (millivolts < 1800)
  54                return 0;
  55        if (millivolts > 3800)
  56                return 0xff;
  57
  58        millivolts -= 625;
  59
  60        return millivolts / 25;
  61}
  62
  63static u8 down_voltage_bits(unsigned int millivolts)
  64{
  65        if (millivolts < 625)
  66                return 0;
  67        else if (millivolts > 3000)
  68                return 0xff;
  69
  70        millivolts -= 625;
  71
  72        return millivolts / 25;
  73}
  74
  75static u8 ldo_voltage_bits(unsigned int millivolts)
  76{
  77        if (millivolts < 900)
  78                return 0;
  79        else if (millivolts > 3600)
  80                return 0x1f;
  81
  82        millivolts -= 900;
  83        return millivolts / 100;
  84}
  85
  86/* Obtain voltage value from bits */
  87static unsigned int auto_voltage_value(u8 bits)
  88{
  89        if (bits < 0x2f)
  90                return 0;
  91
  92        return 625 + (bits * 25);
  93}
  94
  95
  96static unsigned int down_voltage_value(u8 bits)
  97{
  98        return 625 + (bits * 25);
  99}
 100
 101
 102static unsigned int ldo_voltage_value(u8 bits)
 103{
 104        bits &= 0x1f;
 105
 106        return 900 + (bits * 100);
 107}
 108
 109static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
 110                                                int min_uV, int max_uV)
 111{
 112        struct pcf50633 *pcf;
 113        int regulator_id, millivolts;
 114        u8 volt_bits, regnr;
 115
 116        pcf = rdev_get_drvdata(rdev);
 117
 118        regulator_id = rdev_get_id(rdev);
 119        if (regulator_id >= PCF50633_NUM_REGULATORS)
 120                return -EINVAL;
 121
 122        millivolts = min_uV / 1000;
 123
 124        regnr = pcf50633_regulator_registers[regulator_id];
 125
 126        switch (regulator_id) {
 127        case PCF50633_REGULATOR_AUTO:
 128                volt_bits = auto_voltage_bits(millivolts);
 129                break;
 130        case PCF50633_REGULATOR_DOWN1:
 131                volt_bits = down_voltage_bits(millivolts);
 132                break;
 133        case PCF50633_REGULATOR_DOWN2:
 134                volt_bits = down_voltage_bits(millivolts);
 135                break;
 136        case PCF50633_REGULATOR_LDO1:
 137        case PCF50633_REGULATOR_LDO2:
 138        case PCF50633_REGULATOR_LDO3:
 139        case PCF50633_REGULATOR_LDO4:
 140        case PCF50633_REGULATOR_LDO5:
 141        case PCF50633_REGULATOR_LDO6:
 142        case PCF50633_REGULATOR_HCLDO:
 143                volt_bits = ldo_voltage_bits(millivolts);
 144                break;
 145        default:
 146                return -EINVAL;
 147        }
 148
 149        return pcf50633_reg_write(pcf, regnr, volt_bits);
 150}
 151
 152static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
 153{
 154        struct pcf50633 *pcf;
 155        int regulator_id, millivolts, volt_bits;
 156        u8 regnr;
 157
 158        pcf = rdev_get_drvdata(rdev);;
 159
 160        regulator_id = rdev_get_id(rdev);
 161        if (regulator_id >= PCF50633_NUM_REGULATORS)
 162                return -EINVAL;
 163
 164        regnr = pcf50633_regulator_registers[regulator_id];
 165
 166        volt_bits = pcf50633_reg_read(pcf, regnr);
 167        if (volt_bits < 0)
 168                return -1;
 169
 170        switch (regulator_id) {
 171        case PCF50633_REGULATOR_AUTO:
 172                millivolts = auto_voltage_value(volt_bits);
 173                break;
 174        case PCF50633_REGULATOR_DOWN1:
 175                millivolts = down_voltage_value(volt_bits);
 176                break;
 177        case PCF50633_REGULATOR_DOWN2:
 178                millivolts = down_voltage_value(volt_bits);
 179                break;
 180        case PCF50633_REGULATOR_LDO1:
 181        case PCF50633_REGULATOR_LDO2:
 182        case PCF50633_REGULATOR_LDO3:
 183        case PCF50633_REGULATOR_LDO4:
 184        case PCF50633_REGULATOR_LDO5:
 185        case PCF50633_REGULATOR_LDO6:
 186        case PCF50633_REGULATOR_HCLDO:
 187                millivolts = ldo_voltage_value(volt_bits);
 188                break;
 189        default:
 190                return -EINVAL;
 191        }
 192
 193        return millivolts * 1000;
 194}
 195
 196static int pcf50633_regulator_enable(struct regulator_dev *rdev)
 197{
 198        struct pcf50633 *pcf = rdev_get_drvdata(rdev);
 199        int regulator_id;
 200        u8 regnr;
 201
 202        regulator_id = rdev_get_id(rdev);
 203        if (regulator_id >= PCF50633_NUM_REGULATORS)
 204                return -EINVAL;
 205
 206        /* The *ENA register is always one after the *OUT register */
 207        regnr = pcf50633_regulator_registers[regulator_id] + 1;
 208
 209        return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON,
 210                                                       PCF50633_REGULATOR_ON);
 211}
 212
 213static int pcf50633_regulator_disable(struct regulator_dev *rdev)
 214{
 215        struct pcf50633 *pcf = rdev_get_drvdata(rdev);
 216        int regulator_id;
 217        u8 regnr;
 218
 219        regulator_id = rdev_get_id(rdev);
 220        if (regulator_id >= PCF50633_NUM_REGULATORS)
 221                return -EINVAL;
 222
 223        /* the *ENA register is always one after the *OUT register */
 224        regnr = pcf50633_regulator_registers[regulator_id] + 1;
 225
 226        return pcf50633_reg_set_bit_mask(pcf, regnr,
 227                                        PCF50633_REGULATOR_ON, 0);
 228}
 229
 230static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
 231{
 232        struct pcf50633 *pcf = rdev_get_drvdata(rdev);
 233        int regulator_id = rdev_get_id(rdev);
 234        u8 regnr;
 235
 236        regulator_id = rdev_get_id(rdev);
 237        if (regulator_id >= PCF50633_NUM_REGULATORS)
 238                return -EINVAL;
 239
 240        /* the *ENA register is always one after the *OUT register */
 241        regnr = pcf50633_regulator_registers[regulator_id] + 1;
 242
 243        return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON;
 244}
 245
 246static struct regulator_ops pcf50633_regulator_ops = {
 247        .set_voltage = pcf50633_regulator_set_voltage,
 248        .get_voltage = pcf50633_regulator_get_voltage,
 249        .enable = pcf50633_regulator_enable,
 250        .disable = pcf50633_regulator_disable,
 251        .is_enabled = pcf50633_regulator_is_enabled,
 252};
 253
 254static struct regulator_desc regulators[] = {
 255        [PCF50633_REGULATOR_AUTO] =
 256                PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO),
 257        [PCF50633_REGULATOR_DOWN1] =
 258                PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1),
 259        [PCF50633_REGULATOR_DOWN2] =
 260                PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2),
 261        [PCF50633_REGULATOR_LDO1] =
 262                PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1),
 263        [PCF50633_REGULATOR_LDO2] =
 264                PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2),
 265        [PCF50633_REGULATOR_LDO3] =
 266                PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3),
 267        [PCF50633_REGULATOR_LDO4] =
 268                PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4),
 269        [PCF50633_REGULATOR_LDO5] =
 270                PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5),
 271        [PCF50633_REGULATOR_LDO6] =
 272                PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6),
 273        [PCF50633_REGULATOR_HCLDO] =
 274                PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO),
 275        [PCF50633_REGULATOR_MEMLDO] =
 276                PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO),
 277};
 278
 279static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
 280{
 281        struct regulator_dev *rdev;
 282        struct pcf50633 *pcf;
 283
 284        /* Already set by core driver */
 285        pcf = platform_get_drvdata(pdev);
 286
 287        rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
 288                                  pdev->dev.platform_data, pcf);
 289        if (IS_ERR(rdev))
 290                return PTR_ERR(rdev);
 291
 292        if (pcf->pdata->regulator_registered)
 293                pcf->pdata->regulator_registered(pcf, pdev->id);
 294
 295        return 0;
 296}
 297
 298static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
 299{
 300        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 301
 302        regulator_unregister(rdev);
 303
 304        return 0;
 305}
 306
 307static struct platform_driver pcf50633_regulator_driver = {
 308        .driver = {
 309                .name = "pcf50633-regltr",
 310        },
 311        .probe = pcf50633_regulator_probe,
 312        .remove = __devexit_p(pcf50633_regulator_remove),
 313};
 314
 315static int __init pcf50633_regulator_init(void)
 316{
 317        return platform_driver_register(&pcf50633_regulator_driver);
 318}
 319module_init(pcf50633_regulator_init);
 320
 321static void __exit pcf50633_regulator_exit(void)
 322{
 323        platform_driver_unregister(&pcf50633_regulator_driver);
 324}
 325module_exit(pcf50633_regulator_exit);
 326
 327MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 328MODULE_DESCRIPTION("PCF50633 regulator driver");
 329MODULE_LICENSE("GPL");
 330MODULE_ALIAS("platform:pcf50633-regulator");
 331
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.