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, *regulators;
 228        int ret;
 229
 230        np = of_node_get(pdev->dev.parent->of_node);
 231        if (!np)
 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        of_node_put(regulators);
 243        if (ret < 0) {
 244                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
 245                        ret);
 246                return ret;
 247        }
 248
 249        return 0;
 250}
 251
 252static inline struct regulator_init_data *match_init_data(int index)
 253{
 254        return max8907_matches[index].init_data;
 255}
 256
 257static inline struct device_node *match_of_node(int index)
 258{
 259        return max8907_matches[index].of_node;
 260}
 261#else
 262static int max8907_regulator_parse_dt(struct platform_device *pdev)
 263{
 264        return 0;
 265}
 266
 267static inline struct regulator_init_data *match_init_data(int index)
 268{
 269        return NULL;
 270}
 271
 272static inline struct device_node *match_of_node(int index)
 273{
 274        return NULL;
 275}
 276#endif
 277
 278static int max8907_regulator_probe(struct platform_device *pdev)
 279{
 280        struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
 281        struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
 282        int ret;
 283        struct max8907_regulator *pmic;
 284        unsigned int val;
 285        int i;
 286        struct regulator_config config = {};
 287        struct regulator_init_data *idata;
 288        const char *mbatt_rail_name = NULL;
 289
 290        ret = max8907_regulator_parse_dt(pdev);
 291        if (ret)
 292                return ret;
 293
 294        pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
 295        if (!pmic) {
 296                dev_err(&pdev->dev, "Failed to alloc pmic\n");
 297                return -ENOMEM;
 298        }
 299        platform_set_drvdata(pdev, pmic);
 300
 301        memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
 302
 303        /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
 304        regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
 305        if ((val & MAX8907_II2RR_VERSION_MASK) ==
 306            MAX8907_II2RR_VERSION_REV_B) {
 307                pmic->desc[MAX8907_SD1].min_uV = 637500;
 308                pmic->desc[MAX8907_SD1].uV_step = 12500;
 309                pmic->desc[MAX8907_SD1].n_voltages =
 310                                                (1425000 - 637500) / 12500 + 1;
 311        }
 312
 313        for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
 314                config.dev = pdev->dev.parent;
 315                if (pdata)
 316                        idata = pdata->init_data[i];
 317                else
 318                        idata = match_init_data(i);
 319                config.init_data = idata;
 320                config.driver_data = pmic;
 321                config.regmap = max8907->regmap_gen;
 322                config.of_node = match_of_node(i);
 323
 324                switch (pmic->desc[i].id) {
 325                case MAX8907_MBATT:
 326                        if (idata && idata->constraints.name)
 327                                mbatt_rail_name = idata->constraints.name;
 328                        else
 329                                mbatt_rail_name = pmic->desc[i].name;
 330                        break;
 331                case MAX8907_BBAT:
 332                case MAX8907_SDBY:
 333                case MAX8907_VRTC:
 334                        idata->supply_regulator = mbatt_rail_name;
 335                        break;
 336                }
 337
 338                if (pmic->desc[i].ops == &max8907_ldo_ops) {
 339                        regmap_read(config.regmap, pmic->desc[i].enable_reg,
 340                                    &val);
 341                        if ((val & MAX8907_MASK_LDO_SEQ) !=
 342                            MAX8907_MASK_LDO_SEQ)
 343                                pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
 344                } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
 345                        regmap_read(config.regmap, pmic->desc[i].enable_reg,
 346                                    &val);
 347                        if ((val & (MAX8907_MASK_OUT5V_VINEN |
 348                                                MAX8907_MASK_OUT5V_ENSRC)) !=
 349                            MAX8907_MASK_OUT5V_ENSRC)
 350                                pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
 351                }
 352
 353                pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
 354                if (IS_ERR(pmic->rdev[i])) {
 355                        dev_err(&pdev->dev,
 356                                "failed to register %s regulator\n",
 357                                pmic->desc[i].name);
 358                        ret = PTR_ERR(pmic->rdev[i]);
 359                        goto err_unregister_regulator;
 360                }
 361        }
 362
 363        return 0;
 364
 365err_unregister_regulator:
 366        while (--i >= 0)
 367                regulator_unregister(pmic->rdev[i]);
 368        return ret;
 369}
 370
 371static int max8907_regulator_remove(struct platform_device *pdev)
 372{
 373        struct max8907_regulator *pmic = platform_get_drvdata(pdev);
 374        int i;
 375
 376        for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
 377                regulator_unregister(pmic->rdev[i]);
 378
 379        return 0;
 380}
 381
 382static struct platform_driver max8907_regulator_driver = {
 383        .driver = {
 384                   .name = "max8907-regulator",
 385                   .owner = THIS_MODULE,
 386                   },
 387        .probe = max8907_regulator_probe,
 388        .remove = max8907_regulator_remove,
 389};
 390
 391static int __init max8907_regulator_init(void)
 392{
 393        return platform_driver_register(&max8907_regulator_driver);
 394}
 395
 396subsys_initcall(max8907_regulator_init);
 397
 398static void __exit max8907_reg_exit(void)
 399{
 400        platform_driver_unregister(&max8907_regulator_driver);
 401}
 402
 403module_exit(max8907_reg_exit);
 404
 405MODULE_DESCRIPTION("MAX8907 regulator driver");
 406MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
 407MODULE_LICENSE("GPL v2");
 408MODULE_ALIAS("platform:max8907-regulator");
 409
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.