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 void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
 107{
 108        struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
 109        enum lp8788_dvs_state pinstate;
 110
 111        if (!dvs)
 112                return;
 113
 114        pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
 115        if (gpio_is_valid(dvs->gpio))
 116                gpio_set_value(dvs->gpio, pinstate);
 117}
 118
 119static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
 120{
 121        struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
 122        enum lp8788_dvs_state pin1, pin2;
 123
 124        if (!dvs)
 125                return;
 126
 127        switch (dvs->vsel) {
 128        case DVS_SEL_V0:
 129                pin1 = DVS_LOW;
 130                pin2 = DVS_LOW;
 131                break;
 132        case DVS_SEL_V1:
 133                pin1 = DVS_HIGH;
 134                pin2 = DVS_LOW;
 135                break;
 136        case DVS_SEL_V2:
 137                pin1 = DVS_LOW;
 138                pin2 = DVS_HIGH;
 139                break;
 140        case DVS_SEL_V3:
 141                pin1 = DVS_HIGH;
 142                pin2 = DVS_HIGH;
 143                break;
 144        default:
 145                return;
 146        }
 147
 148        if (gpio_is_valid(dvs->gpio[0]))
 149                gpio_set_value(dvs->gpio[0], pin1);
 150
 151        if (gpio_is_valid(dvs->gpio[1]))
 152                gpio_set_value(dvs->gpio[1], pin2);
 153}
 154
 155static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
 156{
 157        switch (id) {
 158        case BUCK1:
 159                lp8788_buck1_set_dvs(buck);
 160                break;
 161        case BUCK2:
 162                lp8788_buck2_set_dvs(buck);
 163                break;
 164        default:
 165                break;
 166        }
 167}
 168
 169static enum lp8788_dvs_mode
 170lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
 171{
 172        u8 val, mask;
 173
 174        switch (id) {
 175        case BUCK1:
 176                mask = LP8788_BUCK1_DVS_SEL_M;
 177                break;
 178        case BUCK2:
 179                mask = LP8788_BUCK2_DVS_SEL_M;
 180                break;
 181        default:
 182                return REGISTER;
 183        }
 184
 185        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 186
 187        return val & mask ? REGISTER : EXTPIN;
 188}
 189
 190static bool lp8788_is_valid_buck_addr(u8 addr)
 191{
 192        switch (addr) {
 193        case LP8788_BUCK1_VOUT0:
 194        case LP8788_BUCK1_VOUT1:
 195        case LP8788_BUCK1_VOUT2:
 196        case LP8788_BUCK1_VOUT3:
 197        case LP8788_BUCK2_VOUT0:
 198        case LP8788_BUCK2_VOUT1:
 199        case LP8788_BUCK2_VOUT2:
 200        case LP8788_BUCK2_VOUT3:
 201                return true;
 202        default:
 203                return false;
 204        }
 205}
 206
 207static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
 208                                        enum lp8788_buck_id id)
 209{
 210        enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
 211        struct lp8788_buck1_dvs *b1_dvs;
 212        struct lp8788_buck2_dvs *b2_dvs;
 213        u8 val, idx, addr;
 214        int pin1, pin2;
 215
 216        switch (id) {
 217        case BUCK1:
 218                if (mode == EXTPIN) {
 219                        b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
 220                        if (!b1_dvs)
 221                                goto err;
 222
 223                        idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
 224                } else {
 225                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 226                        idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
 227                }
 228                addr = LP8788_BUCK1_VOUT0 + idx;
 229                break;
 230        case BUCK2:
 231                if (mode == EXTPIN) {
 232                        b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
 233                        if (!b2_dvs)
 234                                goto err;
 235
 236                        pin1 = gpio_get_value(b2_dvs->gpio[0]);
 237                        pin2 = gpio_get_value(b2_dvs->gpio[1]);
 238
 239                        if (pin1 == PIN_LOW && pin2 == PIN_LOW)
 240                                idx = 0;
 241                        else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
 242                                idx = 2;
 243                        else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
 244                                idx = 1;
 245                        else
 246                                idx = 3;
 247                } else {
 248                        lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 249                        idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
 250                }
 251                addr = LP8788_BUCK2_VOUT0 + idx;
 252                break;
 253        default:
 254                goto err;
 255        }
 256
 257        return addr;
 258err:
 259        return INVALID_ADDR;
 260}
 261
 262static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
 263                                        unsigned selector)
 264{
 265        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 266        enum lp8788_buck_id id = rdev_get_id(rdev);
 267        u8 addr;
 268
 269        if (buck->dvs)
 270                lp8788_set_dvs(buck, id);
 271
 272        addr = lp8788_select_buck_vout_addr(buck, id);
 273        if (!lp8788_is_valid_buck_addr(addr))
 274                return -EINVAL;
 275
 276        return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
 277}
 278
 279static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
 280{
 281        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 282        enum lp8788_buck_id id = rdev_get_id(rdev);
 283        int ret;
 284        u8 val, addr;
 285
 286        addr = lp8788_select_buck_vout_addr(buck, id);
 287        if (!lp8788_is_valid_buck_addr(addr))
 288                return -EINVAL;
 289
 290        ret = lp8788_read_byte(buck->lp, addr, &val);
 291        if (ret)
 292                return ret;
 293
 294        return val & LP8788_VOUT_M;
 295}
 296
 297static int lp8788_buck_enable_time(struct regulator_dev *rdev)
 298{
 299        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 300        enum lp8788_buck_id id = rdev_get_id(rdev);
 301        u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
 302
 303        if (lp8788_read_byte(buck->lp, addr, &val))
 304                return -EINVAL;
 305
 306        val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
 307
 308        return ENABLE_TIME_USEC * val;
 309}
 310
 311static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
 312{
 313        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 314        enum lp8788_buck_id id = rdev_get_id(rdev);
 315        u8 mask, val;
 316
 317        mask = BUCK_FPWM_MASK(id);
 318        switch (mode) {
 319        case REGULATOR_MODE_FAST:
 320                val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);
 321                break;
 322        case REGULATOR_MODE_NORMAL:
 323                val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);
 324                break;
 325        default:
 326                return -EINVAL;
 327        }
 328
 329        return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);
 330}
 331
 332static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
 333{
 334        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
 335        enum lp8788_buck_id id = rdev_get_id(rdev);
 336        u8 val;
 337        int ret;
 338
 339        ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
 340        if (ret)
 341                return ret;
 342
 343        return val & BUCK_FPWM_MASK(id) ?
 344                                REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 345}
 346
 347static struct regulator_ops lp8788_buck12_ops = {
 348        .list_voltage = regulator_list_voltage_table,
 349        .map_voltage = regulator_map_voltage_ascend,
 350        .set_voltage_sel = lp8788_buck12_set_voltage_sel,
 351        .get_voltage_sel = lp8788_buck12_get_voltage_sel,
 352        .enable = regulator_enable_regmap,
 353        .disable = regulator_disable_regmap,
 354        .is_enabled = regulator_is_enabled_regmap,
 355        .enable_time = lp8788_buck_enable_time,
 356        .set_mode = lp8788_buck_set_mode,
 357        .get_mode = lp8788_buck_get_mode,
 358};
 359
 360static struct regulator_ops lp8788_buck34_ops = {
 361        .list_voltage = regulator_list_voltage_table,
 362        .map_voltage = regulator_map_voltage_ascend,
 363        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 364        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 365        .enable = regulator_enable_regmap,
 366        .disable = regulator_disable_regmap,
 367        .is_enabled = regulator_is_enabled_regmap,
 368        .enable_time = lp8788_buck_enable_time,
 369        .set_mode = lp8788_buck_set_mode,
 370        .get_mode = lp8788_buck_get_mode,
 371};
 372
 373static struct regulator_desc lp8788_buck_desc[] = {
 374        {
 375                .name = "buck1",
 376                .id = BUCK1,
 377                .ops = &lp8788_buck12_ops,
 378                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 379                .volt_table = lp8788_buck_vtbl,
 380                .type = REGULATOR_VOLTAGE,
 381                .owner = THIS_MODULE,
 382                .enable_reg = LP8788_EN_BUCK,
 383                .enable_mask = LP8788_EN_BUCK1_M,
 384        },
 385        {
 386                .name = "buck2",
 387                .id = BUCK2,
 388                .ops = &lp8788_buck12_ops,
 389                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 390                .volt_table = lp8788_buck_vtbl,
 391                .type = REGULATOR_VOLTAGE,
 392                .owner = THIS_MODULE,
 393                .enable_reg = LP8788_EN_BUCK,
 394                .enable_mask = LP8788_EN_BUCK2_M,
 395        },
 396        {
 397                .name = "buck3",
 398                .id = BUCK3,
 399                .ops = &lp8788_buck34_ops,
 400                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 401                .volt_table = lp8788_buck_vtbl,
 402                .type = REGULATOR_VOLTAGE,
 403                .owner = THIS_MODULE,
 404                .vsel_reg = LP8788_BUCK3_VOUT,
 405                .vsel_mask = LP8788_VOUT_M,
 406                .enable_reg = LP8788_EN_BUCK,
 407                .enable_mask = LP8788_EN_BUCK3_M,
 408        },
 409        {
 410                .name = "buck4",
 411                .id = BUCK4,
 412                .ops = &lp8788_buck34_ops,
 413                .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
 414                .volt_table = lp8788_buck_vtbl,
 415                .type = REGULATOR_VOLTAGE,
 416                .owner = THIS_MODULE,
 417                .vsel_reg = LP8788_BUCK4_VOUT,
 418                .vsel_mask = LP8788_VOUT_M,
 419                .enable_reg = LP8788_EN_BUCK,
 420                .enable_mask = LP8788_EN_BUCK4_M,
 421        },
 422};
 423
 424static int lp8788_dvs_gpio_request(struct platform_device *pdev,
 425                                struct lp8788_buck *buck,
 426                                enum lp8788_buck_id id)
 427{
 428        struct lp8788_platform_data *pdata = buck->lp->pdata;
 429        char *b1_name = "LP8788_B1_DVS";
 430        char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
 431        int i, gpio, ret;
 432
 433        switch (id) {
 434        case BUCK1:
 435                gpio = pdata->buck1_dvs->gpio;
 436                ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
 437                                            b1_name);
 438                if (ret)
 439                        return ret;
 440
 441                buck->dvs = pdata->buck1_dvs;
 442                break;
 443        case BUCK2:
 444                for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) {
 445                        gpio = pdata->buck2_dvs->gpio[i];
 446                        ret = devm_gpio_request_one(&pdev->dev, gpio,
 447                                                    DVS_LOW, b2_name[i]);
 448                        if (ret)
 449                                return ret;
 450                }
 451                buck->dvs = pdata->buck2_dvs;
 452                break;
 453        default:
 454                break;
 455        }
 456
 457        return 0;
 458}
 459
 460static int lp8788_init_dvs(struct platform_device *pdev,
 461                        struct lp8788_buck *buck, enum lp8788_buck_id id)
 462{
 463        struct lp8788_platform_data *pdata = buck->lp->pdata;
 464        u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
 465        u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
 466        u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 467
 468        /* no dvs for buck3, 4 */
 469        if (id > BUCK2)
 470                return 0;
 471
 472        /* no dvs platform data, then dvs will be selected by I2C registers */
 473        if (!pdata)
 474                goto set_default_dvs_mode;
 475
 476        if ((id == BUCK1 && !pdata->buck1_dvs) ||
 477                (id == BUCK2 && !pdata->buck2_dvs))
 478                goto set_default_dvs_mode;
 479
 480        if (lp8788_dvs_gpio_request(pdev, buck, id))
 481                goto set_default_dvs_mode;
 482
 483        return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
 484                                val[id]);
 485
 486set_default_dvs_mode:
 487        return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
 488                                  default_dvs_mode[id]);
 489}
 490
 491static int lp8788_buck_probe(struct platform_device *pdev)
 492{
 493        struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
 494        int id = pdev->id;
 495        struct lp8788_buck *buck;
 496        struct regulator_config cfg = { };
 497        struct regulator_dev *rdev;
 498        int ret;
 499
 500        if (id >= LP8788_NUM_BUCKS)
 501                return -EINVAL;
 502
 503        buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
 504        if (!buck)
 505                return -ENOMEM;
 506
 507        buck->lp = lp;
 508
 509        ret = lp8788_init_dvs(pdev, buck, id);
 510        if (ret)
 511                return ret;
 512
 513        cfg.dev = pdev->dev.parent;
 514        cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
 515        cfg.driver_data = buck;
 516        cfg.regmap = lp->regmap;
 517
 518        rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
 519        if (IS_ERR(rdev)) {
 520                ret = PTR_ERR(rdev);
 521                dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
 522                                id + 1, ret);
 523                return ret;
 524        }
 525
 526        buck->regulator = rdev;
 527        platform_set_drvdata(pdev, buck);
 528
 529        return 0;
 530}
 531
 532static int lp8788_buck_remove(struct platform_device *pdev)
 533{
 534        struct lp8788_buck *buck = platform_get_drvdata(pdev);
 535
 536        regulator_unregister(buck->regulator);
 537
 538        return 0;
 539}
 540
 541static struct platform_driver lp8788_buck_driver = {
 542        .probe = lp8788_buck_probe,
 543        .remove = lp8788_buck_remove,
 544        .driver = {
 545                .name = LP8788_DEV_BUCK,
 546                .owner = THIS_MODULE,
 547        },
 548};
 549
 550static int __init lp8788_buck_init(void)
 551{
 552        return platform_driver_register(&lp8788_buck_driver);
 553}
 554subsys_initcall(lp8788_buck_init);
 555
 556static void __exit lp8788_buck_exit(void)
 557{
 558        platform_driver_unregister(&lp8788_buck_driver);
 559}
 560module_exit(lp8788_buck_exit);
 561
 562MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
 563MODULE_AUTHOR("Milo Kim");
 564MODULE_LICENSE("GPL");
 565MODULE_ALIAS("platform:lp8788-buck");
 566
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.