linux/drivers/regulator/lp8788-buck.c
<<
>>
Prefs
   1/*
   2 * TI LP8788 MFD - buck regulator driver
   3 *
   4 * Copyright 2012 Texas Instruments
   5 *
   6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/slab.h>
  16#include <linux/err.h>
  17#include <linux/platform_device.h>
  18#include <linux/regulator/driver.h>
  19#include <linux/mfd/lp8788.h>
  20#include <linux/gpio.h>
  21
  22/* register address */
  23#define LP8788_EN_BUCK                  0x0C
  24#define LP8788_BUCK_DVS_SEL             0x1D
  25#define LP8788_BUCK1_VOUT0              0x1E
  26#define LP8788_BUCK1_VOUT1              0x1F
  27#define LP8788_BUCK1_VOUT2              0x20
  28#define LP8788_BUCK1_VOUT3              0x21
  29#define LP8788_BUCK2_VOUT0              0x22
  30#define LP8788_BUCK2_VOUT1              0x23
  31#define LP8788_BUCK2_VOUT2              0x24
  32#define LP8788_BUCK2_VOUT3              0x25
  33#define LP8788_BUCK3_VOUT               0x26
  34#define LP8788_BUCK4_VOUT               0x27
  35#define LP8788_BUCK1_TIMESTEP           0x28
  36#define LP8788_BUCK_PWM                 0x2D
  37
  38/* mask/shift bits */
  39#define LP8788_EN_BUCK1_M               BIT(0)  /* Addr 0Ch */
  40#define LP8788_EN_BUCK2_M               BIT(1)
  41#define LP8788_EN_BUCK3_M               BIT(2)
  42#define LP8788_EN_BUCK4_M               BIT(3)
  43#define LP8788_BUCK1_DVS_SEL_M          0x04    /* Addr 1Dh */
  44#define LP8788_BUCK1_DVS_M              0x03
  45#define LP8788_BUCK1_DVS_S              0
  46#define LP8788_BUCK2_DVS_SEL_M          0x40
  47#define LP8788_BUCK2_DVS_M              0x30
  48#define LP8788_BUCK2_DVS_S              4
  49#define LP8788_BUCK1_DVS_I2C            BIT(2)
  50#define LP8788_BUCK2_DVS_I2C            BIT(6)
  51#define LP8788_BUCK1_DVS_PIN            (0 << 2)
  52#define LP8788_BUCK2_DVS_PIN            (0 << 6)
  53#define LP8788_VOUT_M                   0x1F    /* Addr 1Eh ~ 27h */
  54#define LP8788_STARTUP_TIME_M           0xF8    /* Addr 28h ~ 2Bh */
  55#define LP8788_STARTUP_TIME_S           3
  56#define LP8788_FPWM_BUCK1_M             BIT(0)  /* Addr 2Dh */
  57#define LP8788_FPWM_BUCK1_S             0
  58#define LP8788_FPWM_BUCK2_M             BIT(1)
  59#define LP8788_FPWM_BUCK2_S             1
  60#define LP8788_FPWM_BUCK3_M             BIT(2)
  61#define LP8788_FPWM_BUCK3_S             2
  62#define LP8788_FPWM_BUCK4_M             BIT(3)
  63#define LP8788_FPWM_BUCK4_S             3
  64
  65#define INVALID_ADDR                    0xFF
  66#define LP8788_FORCE_PWM                1
  67#define LP8788_AUTO_PWM                 0
  68#define PIN_LOW                         0
  69#define PIN_HIGH                        1
  70#define ENABLE_TIME_USEC                32
  71
  72#define BUCK_FPWM_MASK(x)               (1 << (x))
  73#define BUCK_FPWM_SHIFT(x)              (x)
  74
  75enum lp8788_dvs_state {
  76        DVS_LOW  = GPIOF_OUT_INIT_LOW,
  77        DVS_HIGH = GPIOF_OUT_INIT_HIGH,
  78};
  79
  80enum lp8788_dvs_mode {
  81        REGISTER,
  82        EXTPIN,
  83};
  84
  85enum lp8788_buck_id {
  86        BUCK1,
  87        BUCK2,
  88        BUCK3,
  89        BUCK4,
  90};
  91
  92struct lp8788_buck {
  93        struct lp8788 *lp;
  94        struct regulator_dev *regulator;
  95        void *dvs;
  96};
  97
  98/* BUCK 1 ~ 4 voltage table */
  99static const int lp8788_buck_vtbl[] = {
 100         500000,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
 101        1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
 102        1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
 103        1950000, 2000000,
 104};
 105
 106static const u8 buck1_vout_addr[] = {
 107        LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
 108        LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
 109};
 110
 111static const u8 buck2_vout_addr[] = {
 112        LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
 113        LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
 114};
 115
 116static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
 117{
 118        struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
 119        enum lp8788_dvs_state pinstate;
 120
 121        if (!dvs)
 122                return;
 123
 124        pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
 125        if (gpio_is_valid(dvs->gpio))
 126                gpio_set_value(dvs->gpio, pinstate);
 127}
 128
 129static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
 130{
 131        struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
 132        enum lp8788_dvs_state pin1, pin2;
 133
 134        if (!dvs)
 135                return;
 136
 137        switch (dvs->vsel) {
 138        case DVS_SEL_V0:
 139                pin1 = DVS_LOW;
 140                pin2 = DVS_LOW;
 141                break;
 142        case DVS_SEL_V1:
 143                pin1 = DVS_HIGH;
 144                pin2 = DVS_LOW;
 145                break;
 146        case DVS_SEL_V2:
 147                pin1 = DVS_LOW;
 148                pin2 = DVS_HIGH;
 149                break;
 150        case DVS_SEL_V3:
 151                pin1 = DVS_HIGH;
 152                pin2 = DVS_HIGH;
 153                break;
 154        default:
 155                return;
 156        }
 157
 158        if (gpio_is_valid(dvs->gpio[0]))
 159                gpio_set_value(dvs->gpio[0], pin1);
 160
 161        if (gpio_is_valid(dvs->gpio[1]))
 162                gpio_set_value(dvs->gpio[1], pin2);
 163}
 164
 165static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
 166{
 167        switch (id) {
 168        case BUCK1:
 169                lp8788_buck1_set_dvs(buck);
 170                break;
 171        case BUCK2:
 172                lp8788_buck2_set_dvs(buck);
 173                break;
 174        default:
 175                break;
 176        }
 177}
 178
 179static enum lp8788_dvs_mode
 180lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
 181{
 182        u8 val, mask;
 183
 184        switch (id) {
 185        case BUCK1:
 186                mask = LP8788_BUCK1_DVS_SEL_M;
 187                break;
 188        case BUCK2:
 189                mask = LP8788_BUCK2_DVS_SEL_M;
 190                break;
 191        default:
 192                return REGISTER;
 193        }
 194
 195        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 196
 197        return val & mask ? REGISTER : EXTPIN;
 198}
 199
 200static bool lp8788_is_valid_buck_addr(u8 addr)
 201{
 202        switch (addr) {
 203        case LP8788_BUCK1_VOUT0:
 204        case LP8788_BUCK1_VOUT1:
 205        case LP8788_BUCK1_VOUT2:
 206        case LP8788_BUCK1_VOUT3:
 207        case LP8788_BUCK2_VOUT0:
 208        case LP8788_BUCK2_VOUT1:
 209        case LP8788_BUCK2_VOUT2:
 210        case LP8788_BUCK2_VOUT3:
 211                return true;
 212        default:
 213                return false;
 214        }
 215}
 216
 217static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
 218                                        enum lp8788_buck_id id)
 219{
 220        enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
 221        struct lp8788_buck1_dvs *b1_dvs;
 222        struct lp8788_buck2_dvs *b2_dvs;
 223        u8 val, idx, addr;
 224        int pin1, pin2;
 225
 226        switch (id) {
 227        case BUCK1:
 228                if (mode == EXTPIN) {
 229                        b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
 230                        if (!b1_dvs)
 231                                goto err;
 232
 233                        idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
 234                } else {
 235                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 236                        idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
 237                }
 238                addr = buck1_vout_addr[idx];
 239                break;
 240        case BUCK2:
 241                if (mode == EXTPIN) {
 242                        b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
 243                        if (!b2_dvs)
 244                                goto err;
 245
 246                        pin1 = gpio_get_value(b2_dvs->gpio[0]);
 247                        pin2 = gpio_get_value(b2_dvs->gpio[1]);
 248
 249                        if (pin1 == PIN_LOW && pin2 == PIN_LOW)
 250                                idx = 0;
 251                        else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
 252                                idx = 2;
 253                        else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
 254                                idx = 1;
 255                        else
 256                                idx = 3;
 257                } else {
 258                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 259                        idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
 260                }
 261                addr = buck2_vout_addr[idx];
 262                break;
 263        default:
 264                goto err;
 265        }
 266
 267        return addr;
 268err:
 269        return INVALID_ADDR;
 270}
 271
 272static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
 273                                        unsigned selector)
 274{
 275        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 276        enum lp8788_buck_id id = rdev_get_id(rdev);
 277        u8 addr;
 278
 279        if (buck->dvs)
 280                lp8788_set_dvs(buck, id);
 281
 282        addr = lp8788_select_buck_vout_addr(buck, id);
 283        if (!lp8788_is_valid_buck_addr(addr))
 284                return -EINVAL;
 285
 286        return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
 287}
 288
 289static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
 290{
 291        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 292        enum lp8788_buck_id id = rdev_get_id(rdev);
 293        int ret;
 294        u8 val, addr;
 295
 296        addr = lp8788_select_buck_vout_addr(buck, id);
 297        if (!lp8788_is_valid_buck_addr(addr))
 298                return -EINVAL;
 299
 300        ret = lp8788_read_byte(buck->lp, addr, &val);
 301        if (ret)
 302                return ret;
 303
 304        return val & LP8788_VOUT_M;
 305}
 306
 307static int lp8788_buck_enable_time(struct regulator_dev *rdev)
 308{
 309        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 310        enum lp8788_buck_id id = rdev_get_id(rdev);
 311        u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
 312
 313        if (lp8788_read_byte(buck->lp, addr, &val))
 314                return -EINVAL;
 315
 316        val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
 317
 318        return ENABLE_TIME_USEC * val;
 319}
 320
 321static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
 322{
 323        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 324        enum lp8788_buck_id id = rdev_get_id(rdev);
 325        u8 mask, val;
 326
 327        mask = BUCK_FPWM_MASK(id);
 328        switch (mode) {
 329        case REGULATOR_MODE_FAST:
 330                val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);
 331                break;
 332        case REGULATOR_MODE_NORMAL:
 333                val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);
 334                break;
 335        default:
 336                return -EINVAL;
 337        }
 338
 339        return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);
 340}
 341
 342static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
 343{
 344        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 345        enum lp8788_buck_id id = rdev_get_id(rdev);
 346        u8 val;
 347        int ret;
 348
 349        ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
 350        if (ret)
 351                return ret;
 352
 353        return val & BUCK_FPWM_MASK(id) ?
 354                                REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 355}
 356
 357static struct regulator_ops lp8788_buck12_ops = {
 358        .list_voltage = regulator_list_voltage_table,
 359        .set_voltage_sel = lp8788_buck12_set_voltage_sel,
 360        .get_voltage_sel = lp8788_buck12_get_voltage_sel,
 361        .enable = regulator_enable_regmap,
 362        .disable = regulator_disable_regmap,
 363        .is_enabled = regulator_is_enabled_regmap,
 364        .enable_time = lp8788_buck_enable_time,
 365        .set_mode = lp8788_buck_set_mode,
 366        .get_mode = lp8788_buck_get_mode,
 367};
 368
 369static struct regulator_ops lp8788_buck34_ops = {
 370        .list_voltage = regulator_list_voltage_table,
 371        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 372        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 373        .enable = regulator_enable_regmap,
 374        .disable = regulator_disable_regmap,
 375        .is_enabled = regulator_is_enabled_regmap,
 376        .enable_time = lp8788_buck_enable_time,
 377        .set_mode = lp8788_buck_set_mode,
 378        .get_mode = lp8788_buck_get_mode,
 379};
 380
 381static struct regulator_desc lp8788_buck_desc[] = {
 382        {
 383                .name = "buck1",
 384                .id = BUCK1,
 385                .ops = &lp8788_buck12_ops,
 386                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 387                .volt_table = lp8788_buck_vtbl,
 388                .type = REGULATOR_VOLTAGE,
 389                .owner = THIS_MODULE,
 390                .enable_reg = LP8788_EN_BUCK,
 391                .enable_mask = LP8788_EN_BUCK1_M,
 392        },
 393        {
 394                .name = "buck2",
 395                .id = BUCK2,
 396                .ops = &lp8788_buck12_ops,
 397                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 398                .volt_table = lp8788_buck_vtbl,
 399                .type = REGULATOR_VOLTAGE,
 400                .owner = THIS_MODULE,
 401                .enable_reg = LP8788_EN_BUCK,
 402                .enable_mask = LP8788_EN_BUCK2_M,
 403        },
 404        {
 405                .name = "buck3",
 406                .id = BUCK3,
 407                .ops = &lp8788_buck34_ops,
 408                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 409                .volt_table = lp8788_buck_vtbl,
 410                .type = REGULATOR_VOLTAGE,
 411                .owner = THIS_MODULE,
 412                .vsel_reg = LP8788_BUCK3_VOUT,
 413                .vsel_mask = LP8788_VOUT_M,
 414                .enable_reg = LP8788_EN_BUCK,
 415                .enable_mask = LP8788_EN_BUCK3_M,
 416        },
 417        {
 418                .name = "buck4",
 419                .id = BUCK4,
 420                .ops = &lp8788_buck34_ops,
 421                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 422                .volt_table = lp8788_buck_vtbl,
 423                .type = REGULATOR_VOLTAGE,
 424                .owner = THIS_MODULE,
 425                .vsel_reg = LP8788_BUCK4_VOUT,
 426                .vsel_mask = LP8788_VOUT_M,
 427                .enable_reg = LP8788_EN_BUCK,
 428                .enable_mask = LP8788_EN_BUCK4_M,
 429        },
 430};
 431
 432static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
 433                                enum lp8788_buck_id id)
 434{
 435        struct lp8788_platform_data *pdata = buck->lp->pdata;
 436        char *b1_name = "LP8788_B1_DVS";
 437        char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
 438        int i, gpio, ret;
 439
 440        switch (id) {
 441        case BUCK1:
 442                gpio = pdata->buck1_dvs->gpio;
 443                ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW,
 444                                            b1_name);
 445                if (ret)
 446                        return ret;
 447
 448                buck->dvs = pdata->buck1_dvs;
 449                break;
 450        case BUCK2:
 451                for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
 452                        gpio = pdata->buck2_dvs->gpio[i];
 453                        ret = devm_gpio_request_one(buck->lp->dev, gpio,
 454                                                    DVS_LOW, b2_name[i]);
 455                        if (ret)
 456                                return ret;
 457                }
 458                buck->dvs = pdata->buck2_dvs;
 459                break;
 460        default:
 461                break;
 462        }
 463
 464        return 0;
 465}
 466
 467static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
 468{
 469        struct lp8788_platform_data *pdata = buck->lp->pdata;
 470        u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
 471        u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
 472        u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 473
 474        /* no dvs for buck3, 4 */
 475        if (id == BUCK3 || id == BUCK4)
 476                return 0;
 477
 478        /* no dvs platform data, then dvs will be selected by I2C registers */
 479        if (!pdata)
 480                goto set_default_dvs_mode;
 481
 482        if ((id == BUCK1 && !pdata->buck1_dvs) ||
 483                (id == BUCK2 && !pdata->buck2_dvs))
 484                goto set_default_dvs_mode;
 485
 486        if (lp8788_dvs_gpio_request(buck, id))
 487                goto set_default_dvs_mode;
 488
 489        return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
 490                                val[id]);
 491
 492set_default_dvs_mode:
 493        return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
 494                                  default_dvs_mode[id]);
 495}
 496
 497static int lp8788_buck_probe(struct platform_device *pdev)
 498{
 499        struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
 500        int id = pdev->id;
 501        struct lp8788_buck *buck;
 502        struct regulator_config cfg = { };
 503        struct regulator_dev *rdev;
 504        int ret;
 505
 506        buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
 507        if (!buck)
 508                return -ENOMEM;
 509
 510        buck->lp = lp;
 511
 512        ret = lp8788_init_dvs(buck, id);
 513        if (ret)
 514                return ret;
 515
 516        cfg.dev = lp->dev;
 517        cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
 518        cfg.driver_data = buck;
 519        cfg.regmap = lp->regmap;
 520
 521        rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
 522        if (IS_ERR(rdev)) {
 523                ret = PTR_ERR(rdev);
 524                dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
 525                                id + 1, ret);
 526                return ret;
 527        }
 528
 529        buck->regulator = rdev;
 530        platform_set_drvdata(pdev, buck);
 531
 532        return 0;
 533}
 534
 535static int lp8788_buck_remove(struct platform_device *pdev)
 536{
 537        struct lp8788_buck *buck = platform_get_drvdata(pdev);
 538
 539        platform_set_drvdata(pdev, NULL);
 540        regulator_unregister(buck->regulator);
 541
 542        return 0;
 543}
 544
 545static struct platform_driver lp8788_buck_driver = {
 546        .probe = lp8788_buck_probe,
 547        .remove = lp8788_buck_remove,
 548        .driver = {
 549                .name = LP8788_DEV_BUCK,
 550                .owner = THIS_MODULE,
 551        },
 552};
 553
 554static int __init lp8788_buck_init(void)
 555{
 556        return platform_driver_register(&lp8788_buck_driver);
 557}
 558subsys_initcall(lp8788_buck_init);
 559
 560static void __exit lp8788_buck_exit(void)
 561{
 562        platform_driver_unregister(&lp8788_buck_driver);
 563}
 564module_exit(lp8788_buck_exit);
 565
 566MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
 567MODULE_AUTHOR("Milo Kim");
 568MODULE_LICENSE("GPL");
 569MODULE_ALIAS("platform:lp8788-buck");
 570
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.