linux/drivers/regulator/cpcap-regulator.c
<<
>>
Prefs
   1/*
   2 * Motorola CPCAP PMIC regulator driver
   3 *
   4 * Based on cpcap-regulator.c from Motorola Linux kernel tree
   5 * Copyright (C) 2009-2011 Motorola, Inc.
   6 *
   7 * Rewritten for mainline kernel to use device tree and regmap
   8 * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation version 2.
  13 *
  14 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  15 * kind, whether express or implied; without even the implied warranty
  16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 * GNU General Public License for more details.
  18 */
  19
  20#include <linux/err.h>
  21#include <linux/module.h>
  22#include <linux/of.h>
  23#include <linux/of_platform.h>
  24#include <linux/regmap.h>
  25#include <linux/regulator/driver.h>
  26#include <linux/regulator/machine.h>
  27#include <linux/regulator/of_regulator.h>
  28#include <linux/mfd/motorola-cpcap.h>
  29
  30/*
  31 * Resource assignment register bits. These seem to control the state
  32 * idle modes adn are used at least for omap4.
  33 */
  34
  35/* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */
  36#define CPCAP_BIT_VSDIO_SEL             BIT(15)
  37#define CPCAP_BIT_VDIG_SEL              BIT(14)
  38#define CPCAP_BIT_VCAM_SEL              BIT(13)
  39#define CPCAP_BIT_SW6_SEL               BIT(12)
  40#define CPCAP_BIT_SW5_SEL               BIT(11)
  41#define CPCAP_BIT_SW4_SEL               BIT(10)
  42#define CPCAP_BIT_SW3_SEL               BIT(9)
  43#define CPCAP_BIT_SW2_SEL               BIT(8)
  44#define CPCAP_BIT_SW1_SEL               BIT(7)
  45
  46/* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */
  47#define CPCAP_BIT_VUSBINT2_SEL          BIT(15)
  48#define CPCAP_BIT_VUSBINT1_SEL          BIT(14)
  49#define CPCAP_BIT_VVIB_SEL              BIT(13)
  50#define CPCAP_BIT_VWLAN1_SEL            BIT(12)
  51#define CPCAP_BIT_VRF1_SEL              BIT(11)
  52#define CPCAP_BIT_VHVIO_SEL             BIT(10)
  53#define CPCAP_BIT_VDAC_SEL              BIT(9)
  54#define CPCAP_BIT_VUSB_SEL              BIT(8)
  55#define CPCAP_BIT_VSIM_SEL              BIT(7)
  56#define CPCAP_BIT_VRFREF_SEL            BIT(6)
  57#define CPCAP_BIT_VPLL_SEL              BIT(5)
  58#define CPCAP_BIT_VFUSE_SEL             BIT(4)
  59#define CPCAP_BIT_VCSI_SEL              BIT(3)
  60#define CPCAP_BIT_SPARE_14_2            BIT(2)
  61#define CPCAP_BIT_VWLAN2_SEL            BIT(1)
  62#define CPCAP_BIT_VRF2_SEL              BIT(0)
  63
  64/* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */
  65#define CPCAP_BIT_VAUDIO_SEL            BIT(0)
  66
  67/*
  68 * Enable register bits. At least CPCAP_BIT_AUDIO_LOW_PWR is generic,
  69 * and not limited to audio regulator. Let's use the Motorola kernel
  70 * naming for now until we have a better understanding of the other
  71 * enable register bits. No idea why BIT(3) is not defined.
  72 */
  73#define CPCAP_BIT_AUDIO_LOW_PWR         BIT(6)
  74#define CPCAP_BIT_AUD_LOWPWR_SPEED      BIT(5)
  75#define CPCAP_BIT_VAUDIOPRISTBY         BIT(4)
  76#define CPCAP_BIT_VAUDIO_MODE1          BIT(2)
  77#define CPCAP_BIT_VAUDIO_MODE0          BIT(1)
  78#define CPCAP_BIT_V_AUDIO_EN            BIT(0)
  79
  80/*
  81 * Off mode configuration bit. Used currently only by SW5 on omap4. There's
  82 * the following comment in Motorola Linux kernel tree for it:
  83 *
  84 * When set in the regulator mode, the regulator assignment will be changed
  85 * to secondary when the regulator is disabled. The mode will be set back to
  86 * primary when the regulator is turned on.
  87 */
  88#define CPCAP_REG_OFF_MODE_SEC          BIT(15)
  89
  90/**
  91 * SoC specific configuraion for CPCAP regulator. There are at least three
  92 * different SoCs each with their own parameters: omap3, omap4 and tegra2.
  93 *
  94 * The assign_reg and assign_mask seem to allow toggling between primary
  95 * and secondary mode that at least omap4 uses for off mode.
  96 */
  97struct cpcap_regulator {
  98        struct regulator_desc rdesc;
  99        const u16 assign_reg;
 100        const u16 assign_mask;
 101        const u16 vsel_shift;
 102};
 103
 104#define CPCAP_REG(_ID, reg, assignment_reg, assignment_mask, val_tbl,   \
 105                mode_mask, volt_mask, volt_shft,                        \
 106                mode_val, off_val, volt_trans_time) {                   \
 107        .rdesc = {                                                      \
 108                .name = #_ID,                                           \
 109                .of_match = of_match_ptr(#_ID),                         \
 110                .ops = &cpcap_regulator_ops,                            \
 111                .regulators_node = of_match_ptr("regulators"),          \
 112                .type = REGULATOR_VOLTAGE,                              \
 113                .id = CPCAP_##_ID,                                      \
 114                .owner = THIS_MODULE,                                   \
 115                .n_voltages = ARRAY_SIZE(val_tbl),                      \
 116                .volt_table = (val_tbl),                                \
 117                .vsel_reg = (reg),                                      \
 118                .vsel_mask = (volt_mask),                               \
 119                .enable_reg = (reg),                                    \
 120                .enable_mask = (mode_mask),                             \
 121                .enable_val = (mode_val),                               \
 122                .disable_val = (off_val),                               \
 123                .ramp_delay = (volt_trans_time),                        \
 124        },                                                              \
 125        .assign_reg = (assignment_reg),                                 \
 126        .assign_mask = (assignment_mask),                               \
 127        .vsel_shift = (volt_shft),                                      \
 128}
 129
 130struct cpcap_ddata {
 131        struct regmap *reg;
 132        struct device *dev;
 133        const struct cpcap_regulator *soc;
 134};
 135
 136enum cpcap_regulator_id {
 137        CPCAP_SW1,
 138        CPCAP_SW2,
 139        CPCAP_SW3,
 140        CPCAP_SW4,
 141        CPCAP_SW5,
 142        CPCAP_SW6,
 143        CPCAP_VCAM,
 144        CPCAP_VCSI,
 145        CPCAP_VDAC,
 146        CPCAP_VDIG,
 147        CPCAP_VFUSE,
 148        CPCAP_VHVIO,
 149        CPCAP_VSDIO,
 150        CPCAP_VPLL,
 151        CPCAP_VRF1,
 152        CPCAP_VRF2,
 153        CPCAP_VRFREF,
 154        CPCAP_VWLAN1,
 155        CPCAP_VWLAN2,
 156        CPCAP_VSIM,
 157        CPCAP_VSIMCARD,
 158        CPCAP_VVIB,
 159        CPCAP_VUSB,
 160        CPCAP_VAUDIO,
 161        CPCAP_NR_REGULATORS,
 162};
 163
 164/*
 165 * We need to also configure regulator idle mode for SoC off mode if
 166 * CPCAP_REG_OFF_MODE_SEC is set.
 167 */
 168static int cpcap_regulator_enable(struct regulator_dev *rdev)
 169{
 170        struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
 171        int error, ignore;
 172
 173        error = regulator_enable_regmap(rdev);
 174        if (error)
 175                return error;
 176
 177        if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
 178                error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
 179                                           regulator->assign_mask,
 180                                           regulator->assign_mask);
 181                if (error)
 182                        ignore = regulator_disable_regmap(rdev);
 183        }
 184
 185        return error;
 186}
 187
 188/*
 189 * We need to also configure regulator idle mode for SoC off mode if
 190 * CPCAP_REG_OFF_MODE_SEC is set.
 191 */
 192static int cpcap_regulator_disable(struct regulator_dev *rdev)
 193{
 194        struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
 195        int error, ignore;
 196
 197        if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
 198                error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
 199                                           regulator->assign_mask, 0);
 200                if (error)
 201                        return error;
 202        }
 203
 204        error = regulator_disable_regmap(rdev);
 205        if (error && (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC)) {
 206                ignore = regmap_update_bits(rdev->regmap, regulator->assign_reg,
 207                                            regulator->assign_mask,
 208                                            regulator->assign_mask);
 209        }
 210
 211        return error;
 212}
 213
 214static unsigned int cpcap_regulator_get_mode(struct regulator_dev *rdev)
 215{
 216        int value;
 217
 218        regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
 219
 220        if (!(value & CPCAP_BIT_AUDIO_LOW_PWR))
 221                return REGULATOR_MODE_STANDBY;
 222
 223        return REGULATOR_MODE_NORMAL;
 224}
 225
 226static int cpcap_regulator_set_mode(struct regulator_dev *rdev,
 227                                    unsigned int mode)
 228{
 229        int value;
 230
 231        switch (mode) {
 232        case REGULATOR_MODE_NORMAL:
 233                value = CPCAP_BIT_AUDIO_LOW_PWR;
 234                break;
 235        case REGULATOR_MODE_STANDBY:
 236                value = 0;
 237                break;
 238        default:
 239                return -EINVAL;
 240        }
 241
 242        return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 243                                  CPCAP_BIT_AUDIO_LOW_PWR, value);
 244}
 245
 246static struct regulator_ops cpcap_regulator_ops = {
 247        .enable = cpcap_regulator_enable,
 248        .disable = cpcap_regulator_disable,
 249        .is_enabled = regulator_is_enabled_regmap,
 250        .list_voltage = regulator_list_voltage_table,
 251        .map_voltage = regulator_map_voltage_iterate,
 252        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 253        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 254        .get_mode = cpcap_regulator_get_mode,
 255        .set_mode = cpcap_regulator_set_mode,
 256};
 257
 258static const unsigned int unknown_val_tbl[] = { 0, };
 259static const unsigned int sw5_val_tbl[] = { 0, 5050000, };
 260static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000,
 261                                             2900000, };
 262static const unsigned int vcsi_val_tbl[] = { 1200000, 1800000, };
 263static const unsigned int vdac_val_tbl[] = { 1200000, 1500000, 1800000,
 264                                             2500000,};
 265static const unsigned int vdig_val_tbl[] = { 1200000, 1350000, 1500000,
 266                                             1875000, };
 267static const unsigned int vfuse_val_tbl[] = { 1500000, 1600000, 1700000,
 268                                              1800000, 1900000, 2000000,
 269                                              2100000, 2200000, 2300000,
 270                                              2400000, 2500000, 2600000,
 271                                              2700000, 3150000, };
 272static const unsigned int vhvio_val_tbl[] = { 2775000, };
 273static const unsigned int vsdio_val_tbl[] = { 1500000, 1600000, 1800000,
 274                                              2600000, 2700000, 2800000,
 275                                              2900000, 3000000, };
 276static const unsigned int vpll_val_tbl[] = { 1200000, 1300000, 1400000,
 277                                             1800000, };
 278/* Quirk: 2775000 is before 2500000 for vrf1 regulator */
 279static const unsigned int vrf1_val_tbl[] = { 2775000, 2500000, };
 280static const unsigned int vrf2_val_tbl[] = { 0, 2775000, };
 281static const unsigned int vrfref_val_tbl[] = { 2500000, 2775000, };
 282static const unsigned int vwlan1_val_tbl[] = { 1800000, 1900000, };
 283static const unsigned int vwlan2_val_tbl[] = { 2775000, 3000000, 3300000,
 284                                               3300000, };
 285static const unsigned int vsim_val_tbl[] = { 1800000, 2900000, };
 286static const unsigned int vsimcard_val_tbl[] = { 1800000, 2900000, };
 287static const unsigned int vvib_val_tbl[] = { 1300000, 1800000, 2000000,
 288                                             3000000, };
 289static const unsigned int vusb_val_tbl[] = { 0, 3300000, };
 290static const unsigned int vaudio_val_tbl[] = { 0, 2775000, };
 291
 292/**
 293 * SoC specific configuration for omap4. The data below is comes from Motorola
 294 * Linux kernel tree. It's basically the values of cpcap_regltr_data,
 295 * cpcap_regulator_mode_values and cpcap_regulator_off_mode_values, see
 296 * CPCAP_REG macro above.
 297 *
 298 * SW1 to SW4 and SW6 seems to be unused for mapphone. Note that VSIM and
 299 * VSIMCARD have a shared resource assignment bit.
 300 */
 301static struct cpcap_regulator omap4_regulators[] = {
 302        CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2,
 303                  CPCAP_BIT_SW1_SEL, unknown_val_tbl,
 304                  0, 0, 0, 0, 0, 0),
 305        CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2,
 306                  CPCAP_BIT_SW2_SEL, unknown_val_tbl,
 307                  0, 0, 0, 0, 0, 0),
 308        CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2,
 309                  CPCAP_BIT_SW3_SEL, unknown_val_tbl,
 310                  0, 0, 0, 0, 0, 0),
 311        CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2,
 312                  CPCAP_BIT_SW4_SEL, unknown_val_tbl,
 313                  0, 0, 0, 0, 0, 0),
 314        CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2,
 315                  CPCAP_BIT_SW5_SEL, sw5_val_tbl,
 316                  0x28, 0, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0),
 317        CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2,
 318                  CPCAP_BIT_SW6_SEL, unknown_val_tbl,
 319                  0, 0, 0, 0, 0, 0),
 320        CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2,
 321                  CPCAP_BIT_VCAM_SEL, vcam_val_tbl,
 322                  0x87, 0x30, 4, 0x3, 0, 420),
 323        CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3,
 324                  CPCAP_BIT_VCSI_SEL, vcsi_val_tbl,
 325                  0x47, 0x10, 4, 0x43, 0x41, 350),
 326        CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3,
 327                  CPCAP_BIT_VDAC_SEL, vdac_val_tbl,
 328                  0x87, 0x30, 4, 0x3, 0, 420),
 329        CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2,
 330                  CPCAP_BIT_VDIG_SEL, vdig_val_tbl,
 331                  0x87, 0x30, 4, 0x82, 0, 420),
 332        CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3,
 333                  CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl,
 334                  0x80, 0xf, 0, 0x80, 0, 420),
 335        CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3,
 336                  CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl,
 337                  0x17, 0, 0, 0, 0x12, 0),
 338        CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2,
 339                  CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl,
 340                  0x87, 0x38, 3, 0x82, 0, 420),
 341        CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3,
 342                  CPCAP_BIT_VPLL_SEL, vpll_val_tbl,
 343                  0x43, 0x18, 3, 0x2, 0, 420),
 344        CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3,
 345                  CPCAP_BIT_VRF1_SEL, vrf1_val_tbl,
 346                  0xac, 0x2, 1, 0x4, 0, 10),
 347        CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3,
 348                  CPCAP_BIT_VRF2_SEL, vrf2_val_tbl,
 349                  0x23, 0x8, 3, 0, 0, 10),
 350        CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3,
 351                  CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl,
 352                  0x23, 0x8, 3, 0, 0, 420),
 353        CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3,
 354                  CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl,
 355                  0x47, 0x10, 4, 0, 0, 420),
 356        CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3,
 357                  CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl,
 358                  0x20c, 0xc0, 6, 0x20c, 0, 420),
 359        CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
 360                  0xffff, vsim_val_tbl,
 361                  0x23, 0x8, 3, 0x3, 0, 420),
 362        CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
 363                  0xffff, vsimcard_val_tbl,
 364                  0x1e80, 0x8, 3, 0x1e00, 0, 420),
 365        CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3,
 366                  CPCAP_BIT_VVIB_SEL, vvib_val_tbl,
 367                  0x1, 0xc, 2, 0x1, 0, 500),
 368        CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3,
 369                  CPCAP_BIT_VUSB_SEL, vusb_val_tbl,
 370                  0x11c, 0x40, 6, 0xc, 0, 0),
 371        CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4,
 372                  CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl,
 373                  0x16, 0x1, 0, 0x4, 0, 0),
 374        { /* sentinel */ },
 375};
 376
 377static const struct of_device_id cpcap_regulator_id_table[] = {
 378        {
 379                .compatible = "motorola,cpcap-regulator",
 380        },
 381        {
 382                .compatible = "motorola,mapphone-cpcap-regulator",
 383                .data = omap4_regulators,
 384        },
 385        {},
 386};
 387MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table);
 388
 389static int cpcap_regulator_probe(struct platform_device *pdev)
 390{
 391        struct cpcap_ddata *ddata;
 392        const struct of_device_id *match;
 393        struct regulator_config config;
 394        struct regulator_init_data init_data;
 395        int i;
 396
 397        match = of_match_device(of_match_ptr(cpcap_regulator_id_table),
 398                                &pdev->dev);
 399        if (!match)
 400                return -EINVAL;
 401
 402        if (!match->data) {
 403                dev_err(&pdev->dev, "no configuration data found\n");
 404
 405                return -ENODEV;
 406        }
 407
 408        ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
 409        if (!ddata)
 410                return -ENOMEM;
 411
 412        ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
 413        if (!ddata->reg)
 414                return -ENODEV;
 415
 416        ddata->dev = &pdev->dev;
 417        ddata->soc = match->data;
 418        platform_set_drvdata(pdev, ddata);
 419
 420        memset(&config, 0, sizeof(config));
 421        memset(&init_data, 0, sizeof(init_data));
 422        config.dev = &pdev->dev;
 423        config.regmap = ddata->reg;
 424        config.init_data = &init_data;
 425
 426        for (i = 0; i < CPCAP_NR_REGULATORS; i++) {
 427                const struct cpcap_regulator *regulator = &ddata->soc[i];
 428                struct regulator_dev *rdev;
 429
 430                if (!regulator->rdesc.name)
 431                        break;
 432
 433                if (regulator->rdesc.volt_table == unknown_val_tbl)
 434                        continue;
 435
 436                config.driver_data = (void *)regulator;
 437                rdev = devm_regulator_register(&pdev->dev,
 438                                               &regulator->rdesc,
 439                                               &config);
 440                if (IS_ERR(rdev)) {
 441                        dev_err(&pdev->dev, "failed to register regulator %s\n",
 442                                regulator->rdesc.name);
 443
 444                        return PTR_ERR(rdev);
 445                }
 446        }
 447
 448        return 0;
 449}
 450
 451static struct platform_driver cpcap_regulator_driver = {
 452        .probe          = cpcap_regulator_probe,
 453        .driver         = {
 454                .name   = "cpcap-regulator",
 455                .of_match_table = of_match_ptr(cpcap_regulator_id_table),
 456        },
 457};
 458
 459module_platform_driver(cpcap_regulator_driver);
 460
 461MODULE_ALIAS("platform:cpcap-regulator");
 462MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
 463MODULE_DESCRIPTION("CPCAP regulator driver");
 464MODULE_LICENSE("GPL v2");
 465