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, _n)                      \
  28        {                                                       \
  29                .name = _name,                                  \
  30                .id = PCF50633_REGULATOR_##_id,                 \
  31                .ops = &pcf50633_regulator_ops,                 \
  32                .n_voltages = _n,                               \
  33                .type = REGULATOR_VOLTAGE,                      \
  34                .owner = THIS_MODULE,                           \
  35                .vsel_reg = PCF50633_REG_##_id##OUT,            \
  36                .vsel_mask = 0xff,                              \
  37                .enable_reg = PCF50633_REG_##_id##OUT + 1,      \
  38                .enable_mask = PCF50633_REGULATOR_ON,           \
  39        }
  40
  41/* Bits from voltage value */
  42static u8 auto_voltage_bits(unsigned int millivolts)
  43{
  44        if (millivolts < 1800)
  45                return 0x2f;
  46        if (millivolts > 3800)
  47                return 0xff;
  48
  49        millivolts -= 625;
  50
  51        return millivolts / 25;
  52}
  53
  54static u8 down_voltage_bits(unsigned int millivolts)
  55{
  56        if (millivolts < 625)
  57                return 0;
  58        else if (millivolts > 3000)
  59                return 0xff;
  60
  61        millivolts -= 625;
  62
  63        return millivolts / 25;
  64}
  65
  66static u8 ldo_voltage_bits(unsigned int millivolts)
  67{
  68        if (millivolts < 900)
  69                return 0;
  70        else if (millivolts > 3600)
  71                return 0x1f;
  72
  73        millivolts -= 900;
  74        return millivolts / 100;
  75}
  76
  77/* Obtain voltage value from bits */
  78static unsigned int auto_voltage_value(u8 bits)
  79{
  80        /* AUTOOUT: 00000000 to 00101110 are reserved.
  81         * Return 0 for bits in reserved range, which means this selector code
  82         * can't be used on this system */
  83        if (bits < 0x2f)
  84                return 0;
  85
  86        return 625 + (bits * 25);
  87}
  88
  89
  90static unsigned int down_voltage_value(u8 bits)
  91{
  92        return 625 + (bits * 25);
  93}
  94
  95
  96static unsigned int ldo_voltage_value(u8 bits)
  97{
  98        bits &= 0x1f;
  99
 100        return 900 + (bits * 100);
 101}
 102
 103static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev,
 104                                          int min_uV, int max_uV)
 105{
 106        struct pcf50633 *pcf;
 107        int regulator_id, millivolts;
 108        u8 volt_bits;
 109
 110        pcf = rdev_get_drvdata(rdev);
 111
 112        regulator_id = rdev_get_id(rdev);
 113        if (regulator_id >= PCF50633_NUM_REGULATORS)
 114                return -EINVAL;
 115
 116        millivolts = min_uV / 1000;
 117
 118        switch (regulator_id) {
 119        case PCF50633_REGULATOR_AUTO:
 120                volt_bits = auto_voltage_bits(millivolts);
 121                break;
 122        case PCF50633_REGULATOR_DOWN1:
 123        case PCF50633_REGULATOR_DOWN2:
 124                volt_bits = down_voltage_bits(millivolts);
 125                break;
 126        case PCF50633_REGULATOR_LDO1:
 127        case PCF50633_REGULATOR_LDO2:
 128        case PCF50633_REGULATOR_LDO3:
 129        case PCF50633_REGULATOR_LDO4:
 130        case PCF50633_REGULATOR_LDO5:
 131        case PCF50633_REGULATOR_LDO6:
 132        case PCF50633_REGULATOR_HCLDO:
 133        case PCF50633_REGULATOR_MEMLDO:
 134                volt_bits = ldo_voltage_bits(millivolts);
 135                break;
 136        default:
 137                return -EINVAL;
 138        }
 139
 140        return volt_bits;
 141}
 142
 143static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
 144                                                unsigned int index)
 145{
 146        int regulator_id = rdev_get_id(rdev);
 147
 148        int millivolts;
 149
 150        switch (regulator_id) {
 151        case PCF50633_REGULATOR_AUTO:
 152                millivolts = auto_voltage_value(index);
 153                break;
 154        case PCF50633_REGULATOR_DOWN1:
 155        case PCF50633_REGULATOR_DOWN2:
 156                millivolts = down_voltage_value(index);
 157                break;
 158        case PCF50633_REGULATOR_LDO1:
 159        case PCF50633_REGULATOR_LDO2:
 160        case PCF50633_REGULATOR_LDO3:
 161        case PCF50633_REGULATOR_LDO4:
 162        case PCF50633_REGULATOR_LDO5:
 163        case PCF50633_REGULATOR_LDO6:
 164        case PCF50633_REGULATOR_HCLDO:
 165        case PCF50633_REGULATOR_MEMLDO:
 166                millivolts = ldo_voltage_value(index);
 167                break;
 168        default:
 169                return -EINVAL;
 170        }
 171
 172        return millivolts * 1000;
 173}
 174
 175static struct regulator_ops pcf50633_regulator_ops = {
 176        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 177        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 178        .list_voltage = pcf50633_regulator_list_voltage,
 179        .map_voltage = pcf50633_regulator_map_voltage,
 180        .enable = regulator_enable_regmap,
 181        .disable = regulator_disable_regmap,
 182        .is_enabled = regulator_is_enabled_regmap,
 183};
 184
 185static const struct regulator_desc regulators[] = {
 186        [PCF50633_REGULATOR_AUTO] = PCF50633_REGULATOR("auto", AUTO, 128),
 187        [PCF50633_REGULATOR_DOWN1] = PCF50633_REGULATOR("down1", DOWN1, 96),
 188        [PCF50633_REGULATOR_DOWN2] = PCF50633_REGULATOR("down2", DOWN2, 96),
 189        [PCF50633_REGULATOR_LDO1] = PCF50633_REGULATOR("ldo1", LDO1, 28),
 190        [PCF50633_REGULATOR_LDO2] = PCF50633_REGULATOR("ldo2", LDO2, 28),
 191        [PCF50633_REGULATOR_LDO3] = PCF50633_REGULATOR("ldo3", LDO3, 28),
 192        [PCF50633_REGULATOR_LDO4] = PCF50633_REGULATOR("ldo4", LDO4, 28),
 193        [PCF50633_REGULATOR_LDO5] = PCF50633_REGULATOR("ldo5", LDO5, 28),
 194        [PCF50633_REGULATOR_LDO6] = PCF50633_REGULATOR("ldo6", LDO6, 28),
 195        [PCF50633_REGULATOR_HCLDO] = PCF50633_REGULATOR("hcldo", HCLDO, 28),
 196        [PCF50633_REGULATOR_MEMLDO] = PCF50633_REGULATOR("memldo", MEMLDO, 28),
 197};
 198
 199static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
 200{
 201        struct regulator_dev *rdev;
 202        struct pcf50633 *pcf;
 203        struct regulator_config config = { };
 204
 205        /* Already set by core driver */
 206        pcf = dev_to_pcf50633(pdev->dev.parent);
 207
 208        config.dev = &pdev->dev;
 209        config.init_data = pdev->dev.platform_data;
 210        config.driver_data = pcf;
 211        config.regmap = pcf->regmap;
 212
 213        rdev = regulator_register(&regulators[pdev->id], &config);
 214        if (IS_ERR(rdev))
 215                return PTR_ERR(rdev);
 216
 217        platform_set_drvdata(pdev, rdev);
 218
 219        if (pcf->pdata->regulator_registered)
 220                pcf->pdata->regulator_registered(pcf, pdev->id);
 221
 222        return 0;
 223}
 224
 225static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
 226{
 227        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 228
 229        platform_set_drvdata(pdev, NULL);
 230        regulator_unregister(rdev);
 231
 232        return 0;
 233}
 234
 235static struct platform_driver pcf50633_regulator_driver = {
 236        .driver = {
 237                .name = "pcf50633-regltr",
 238        },
 239        .probe = pcf50633_regulator_probe,
 240        .remove = __devexit_p(pcf50633_regulator_remove),
 241};
 242
 243static int __init pcf50633_regulator_init(void)
 244{
 245        return platform_driver_register(&pcf50633_regulator_driver);
 246}
 247subsys_initcall(pcf50633_regulator_init);
 248
 249static void __exit pcf50633_regulator_exit(void)
 250{
 251        platform_driver_unregister(&pcf50633_regulator_driver);
 252}
 253module_exit(pcf50633_regulator_exit);
 254
 255MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 256MODULE_DESCRIPTION("PCF50633 regulator driver");
 257MODULE_LICENSE("GPL");
 258MODULE_ALIAS("platform:pcf50633-regulator");
 259
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.