linux/drivers/regulator/max8907-regulator.c
<<
>>
Prefs
   1/*
   2 * max8907-regulator.c -- support regulators in max8907
   3 *
   4 * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
   5 * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
   6 *
   7 * Portions based on drivers/regulator/tps65910-regulator.c,
   8 *     Copyright 2010 Texas Instruments Inc.
   9 *     Author: Graeme Gregory <gg@slimlogic.co.uk>
  10 *     Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 */
  16
  17#include <linux/err.h>
  18#include <linux/init.h>
  19#include <linux/mfd/core.h>
  20#include <linux/mfd/max8907.h>
  21#include <linux/module.h>
  22#include <linux/of.h>
  23#include <linux/platform_device.h>
  24#include <linux/regulator/driver.h>
  25#include <linux/regulator/machine.h>
  26#include <linux/regulator/of_regulator.h>
  27#include <linux/regmap.h>
  28#include <linux/slab.h>
  29
  30#define MAX8907_II2RR_VERSION_MASK      0xF0
  31#define MAX8907_II2RR_VERSION_REV_A     0x00
  32#define MAX8907_II2RR_VERSION_REV_B     0x10
  33#define MAX8907_II2RR_VERSION_REV_C     0x30
  34
  35struct max8907_regulator {
  36        struct regulator_desc desc[MAX8907_NUM_REGULATORS];
  37        struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
  38};
  39
  40#define REG_MBATT() \
  41        [MAX8907_MBATT] = { \
  42                .name = "MBATT", \
  43                .supply_name = "mbatt", \
  44                .id = MAX8907_MBATT, \
  45                .ops = &max8907_mbatt_ops, \
  46                .type = REGULATOR_VOLTAGE, \
  47                .owner = THIS_MODULE, \
  48        }
  49
  50#define REG_LDO(ids, supply, base, min, max, step) \
  51        [MAX8907_##ids] = { \
  52                .name = #ids, \
  53                .supply_name = supply, \
  54                .id = MAX8907_##ids, \
  55                .n_voltages = ((max) - (min)) / (step) + 1, \
  56                .ops = &max8907_ldo_ops, \
  57                .type = REGULATOR_VOLTAGE, \
  58                .owner = THIS_MODULE, \
  59                .min_uV = (min), \
  60                .uV_step = (step), \
  61                .vsel_reg = (base) + MAX8907_VOUT, \
  62                .vsel_mask = 0x3f, \
  63                .enable_reg = (base) + MAX8907_CTL, \
  64                .enable_mask = MAX8907_MASK_LDO_EN, \
  65        }
  66
  67#define REG_FIXED(ids, supply, voltage) \
  68        [MAX8907_##ids] = { \
  69                .name = #ids, \
  70                .supply_name = supply, \
  71                .id = MAX8907_##ids, \
  72                .n_voltages = 1, \
  73                .ops = &max8907_fixed_ops, \
  74                .type = REGULATOR_VOLTAGE, \
  75                .owner = THIS_MODULE, \
  76                .min_uV = (voltage), \
  77        }
  78
  79#define REG_OUT5V(ids, supply, base, voltage) \
  80        [MAX8907_##ids] = { \
  81                .name = #ids, \
  82                .supply_name = supply, \
  83                .id = MAX8907_##ids, \
  84                .n_voltages = 1, \
  85                .ops = &max8907_out5v_ops, \
  86                .type = REGULATOR_VOLTAGE, \
  87                .owner = THIS_MODULE, \
  88                .min_uV = (voltage), \
  89                .enable_reg = (base), \
  90                .enable_mask = MAX8907_MASK_OUT5V_EN, \
  91        }
  92
  93#define REG_BBAT(ids, supply, base, min, max, step) \
  94        [MAX8907_##ids] = { \
  95                .name = #ids, \
  96                .supply_name = supply, \
  97                .id = MAX8907_##ids, \
  98                .n_voltages = ((max) - (min)) / (step) + 1, \
  99                .ops = &max8907_bbat_ops, \
 100                .type = REGULATOR_VOLTAGE, \
 101                .owner = THIS_MODULE, \
 102                .min_uV = (min), \
 103                .uV_step = (step), \
 104                .vsel_reg = (base), \
 105                .vsel_mask = MAX8907_MASK_VBBATTCV, \
 106        }
 107
 108#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
 109                        750000, 3900000, 50000)
 110#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
 111                        650000, 2225000, 25000)
 112
 113static struct regulator_ops max8907_mbatt_ops = {
 114};
 115
 116static struct regulator_ops max8907_ldo_ops = {
 117        .list_voltage = regulator_list_voltage_linear,
 118        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 119        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 120        .enable = regulator_enable_regmap,
 121        .disable = regulator_disable_regmap,
 122        .is_enabled = regulator_is_enabled_regmap,
 123};
 124
 125static struct regulator_ops max8907_ldo_hwctl_ops = {
 126        .list_voltage = regulator_list_voltage_linear,
 127        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 128        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 129};
 130
 131static struct regulator_ops max8907_fixed_ops = {
 132        .list_voltage = regulator_list_voltage_linear,
 133};
 134
 135static struct regulator_ops max8907_out5v_ops = {
 136        .list_voltage = regulator_list_voltage_linear,
 137        .enable = regulator_enable_regmap,
 138        .disable = regulator_disable_regmap,
 139        .is_enabled = regulator_is_enabled_regmap,
 140};
 141
 142static struct regulator_ops max8907_out5v_hwctl_ops = {
 143        .list_voltage = regulator_list_voltage_linear,
 144};
 145
 146static struct regulator_ops max8907_bbat_ops = {
 147        .list_voltage = regulator_list_voltage_linear,
 148        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 149        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 150};
 151
 152static struct regulator_desc max8907_regulators[] = {
 153        REG_MBATT(),
 154        REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
 155        REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
 156        REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
 157        LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
 158        LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
 159        LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
 160        LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
 161        LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
 162        LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
 163        LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
 164        LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
 165        LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
 166        LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
 167        LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
 168        LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
 169        LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
 170        LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
 171        LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
 172        LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
 173        LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
 174        LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
 175        LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
 176        LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
 177        REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
 178        REG_OUT5V(OUT33V, "mbatt",  MAX8907_REG_OUT33VEN, 3300000),
 179        REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
 180                                                2400000, 3000000, 200000),
 181        REG_FIXED(SDBY, "MBATT", 1200000),
 182        REG_FIXED(VRTC, "MBATT", 3300000),
 183};
 184
 185#ifdef CONFIG_OF
 186
 187#define MATCH(_name, _id) \
 188        [MAX8907_##_id] = { \
 189                .name = #_name, \
 190                .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
 191        }
 192
 193static struct of_regulator_match max8907_matches[] = {
 194        MATCH(mbatt, MBATT),
 195        MATCH(sd1, SD1),
 196        MATCH(sd2, SD2),
 197        MATCH(sd3, SD3),
 198        MATCH(ldo1, LDO1),
 199        MATCH(ldo2, LDO2),
 200        MATCH(ldo3, LDO3),
 201        MATCH(ldo4, LDO4),
 202        MATCH(ldo5, LDO5),
 203        MATCH(ldo6, LDO6),
 204        MATCH(ldo7, LDO7),
 205        MATCH(ldo8, LDO8),
 206        MATCH(ldo9, LDO9),
 207        MATCH(ldo10, LDO10),
 208        MATCH(ldo11, LDO11),
 209        MATCH(ldo12, LDO12),
 210        MATCH(ldo13, LDO13),
 211        MATCH(ldo14, LDO14),
 212        MATCH(ldo15, LDO15),
 213        MATCH(ldo16, LDO16),
 214        MATCH(ldo17, LDO17),
 215        MATCH(ldo18, LDO18),
 216        MATCH(ldo19, LDO19),
 217        MATCH(ldo20, LDO20),
 218        MATCH(out5v, OUT5V),
 219        MATCH(out33v, OUT33V),
 220        MATCH(bbat, BBAT),
 221        MATCH(sdby, SDBY),
 222        MATCH(vrtc, VRTC),
 223};
 224
 225static int max8907_regulator_parse_dt(struct platform_device *pdev)
 226{
 227        struct device_node *np = pdev->dev.parent->of_node;
 228        struct device_node *regulators;
 229        int ret;
 230
 231        if (!pdev->dev.parent->of_node)
 232                return 0;
 233
 234        regulators = of_find_node_by_name(np, "regulators");
 235        if (!regulators) {
 236                dev_err(&pdev->dev, "regulators node not found\n");
 237                return -EINVAL;
 238        }
 239
 240        ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
 241                                 ARRAY_SIZE(max8907_matches));
 242        if (ret < 0) {
 243                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
 244                        ret);
 245                return ret;
 246        }
 247
 248        return 0;
 249}
 250
 251static inline struct regulator_init_data *match_init_data(int index)
 252{
 253        return max8907_matches[index].init_data;
 254}
 255
 256static inline struct device_node *match_of_node(int index)
 257{
 258        return max8907_matches[index].of_node;
 259}
 260#else
 261static int max8907_regulator_parse_dt(struct platform_device *pdev)
 262{
 263        return 0;
 264}
 265
 266static inline struct regulator_init_data *match_init_data(int index)
 267{
 268        return NULL;
 269}
 270
 271static inline struct device_node *match_of_node(int index)
 272{
 273        return NULL;
 274}
 275#endif
 276
 277static int max8907_regulator_probe(struct platform_device *pdev)
 278{
 279        struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
 280        struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
 281        int ret;
 282        struct max8907_regulator *pmic;
 283        unsigned int val;
 284        int i;
 285        struct regulator_config config = {};
 286        struct regulator_init_data *idata;
 287        const char *mbatt_rail_name = NULL;
 288
 289        ret = max8907_regulator_parse_dt(pdev);
 290        if (ret)
 291                return ret;
 292
 293        pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
 294        if (!pmic) {
 295                dev_err(&pdev->dev, "Failed to alloc pmic\n");
 296                return -ENOMEM;
 297        }
 298        platform_set_drvdata(pdev, pmic);
 299
 300        memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
 301
 302        /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
 303        regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
 304        if ((val & MAX8907_II2RR_VERSION_MASK) ==
 305            MAX8907_II2RR_VERSION_REV_B) {
 306                pmic->desc[MAX8907_SD1].min_uV = 637500;
 307                pmic->desc[MAX8907_SD1].uV_step = 12500;
 308                pmic->desc[MAX8907_SD1].n_voltages =
 309                                                (1425000 - 637500) / 12500 + 1;
 310        }
 311
 312        for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
 313                config.dev = pdev->dev.parent;
 314                if (pdata)
 315                        idata = pdata->init_data[i];
 316                else
 317                        idata = match_init_data(i);
 318                config.init_data = idata;
 319                config.driver_data = pmic;
 320                config.regmap = max8907->regmap_gen;
 321                config.of_node = match_of_node(i);
 322
 323                switch (pmic->desc[i].id) {
 324                case MAX8907_MBATT:
 325                        if (idata && idata->constraints.name)
 326                                mbatt_rail_name = idata->constraints.name;
 327                        else
 328                                mbatt_rail_name = pmic->desc[i].name;
 329                        break;
 330                case MAX8907_BBAT:
 331                case MAX8907_SDBY:
 332                case MAX8907_VRTC:
 333                        idata->supply_regulator = mbatt_rail_name;
 334                        break;
 335                }
 336
 337                if (pmic->desc[i].ops == &max8907_ldo_ops) {
 338                        regmap_read(config.regmap, pmic->desc[i].enable_reg,
 339                                    &val);
 340                        if ((val & MAX8907_MASK_LDO_SEQ) !=
 341                            MAX8907_MASK_LDO_SEQ)
 342                                pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
 343                } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
 344                        regmap_read(config.regmap, pmic->desc[i].enable_reg,
 345                                    &val);
 346                        if ((val & (MAX8907_MASK_OUT5V_VINEN |
 347                                                MAX8907_MASK_OUT5V_ENSRC)) !=
 348                            MAX8907_MASK_OUT5V_ENSRC)
 349                                pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
 350                }
 351
 352                pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
 353                if (IS_ERR(pmic->rdev[i])) {
 354                        dev_err(&pdev->dev,
 355                                "failed to register %s regulator\n",
 356                                pmic->desc[i].name);
 357                        ret = PTR_ERR(pmic->rdev[i]);
 358                        goto err_unregister_regulator;
 359                }
 360        }
 361
 362        return 0;
 363
 364err_unregister_regulator:
 365        while (--i >= 0)
 366                regulator_unregister(pmic->rdev[i]);
 367        return ret;
 368}
 369
 370static int max8907_regulator_remove(struct platform_device *pdev)
 371{
 372        struct max8907_regulator *pmic = platform_get_drvdata(pdev);
 373        int i;
 374
 375        for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
 376                regulator_unregister(pmic->rdev[i]);
 377
 378        return 0;
 379}
 380
 381static struct platform_driver max8907_regulator_driver = {
 382        .driver = {
 383                   .name = "max8907-regulator",
 384                   .owner = THIS_MODULE,
 385                   },
 386        .probe = max8907_regulator_probe,
 387        .remove = max8907_regulator_remove,
 388};
 389
 390static int __init max8907_regulator_init(void)
 391{
 392        return platform_driver_register(&max8907_regulator_driver);
 393}
 394
 395subsys_initcall(max8907_regulator_init);
 396
 397static void __exit max8907_reg_exit(void)
 398{
 399        platform_driver_unregister(&max8907_regulator_driver);
 400}
 401
 402module_exit(max8907_reg_exit);
 403
 404MODULE_DESCRIPTION("MAX8907 regulator driver");
 405MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
 406MODULE_LICENSE("GPL v2");
 407MODULE_ALIAS("platform:max8907-regulator");
 408
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.