1204431Sraj// SPDX-License-Identifier: GPL-2.0+ 2204431Sraj/* 3204431Sraj * (C) Copyright 2016 4204431Sraj * Texas Instruments Incorporated, <www.ti.com> 5204431Sraj * 6204431Sraj * Keerthy <j-keerthy@ti.com> 7204431Sraj */ 8204431Sraj 9204431Sraj#include <common.h> 10204431Sraj#include <fdtdec.h> 11204431Sraj#include <errno.h> 12204431Sraj#include <dm.h> 13204431Sraj#include <power/pmic.h> 14204431Sraj#include <power/regulator.h> 15204431Sraj#include <power/palmas.h> 16204431Sraj 17204431Sraj#define REGULATOR_ON 0x1 18204431Sraj#define REGULATOR_OFF 0x0 19204431Sraj 20204431Sraj#define SMPS_MODE_MASK 0x3 21204431Sraj#define SMPS_MODE_SHIFT 0x0 22204431Sraj#define LDO_MODE_MASK 0x1 23204431Sraj#define LDO_MODE_SHIFT 0x0 24204431Sraj 25204431Srajstatic const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = { 26204431Sraj {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c}, 27204431Sraj {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38}, 28204431Sraj {0x20, 0x24, 0x2c, 0x30, 0x38}, 29204431Sraj}; 30204431Sraj 31204431Srajstatic const char palmas_smps_volt[][PALMAS_SMPS_NUM] = { 32204431Sraj {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c}, 33204431Sraj {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b}, 34204431Sraj {0x23, 0x27, 0x2f, 0x33, 0x3B} 35204431Sraj}; 36204431Sraj 37204431Srajstatic const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = { 38204431Sraj {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64}, 39204431Sraj {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64}, 40204431Sraj {0x50, 0x52, 0x54, 0x5e, 0x62} 41204431Sraj}; 42204431Sraj 43204431Srajstatic const char palmas_ldo_volt[][PALMAS_LDO_NUM] = { 44204431Sraj {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65}, 45204431Sraj {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65}, 46204431Sraj {0x51, 0x53, 0x55, 0x5f, 0x63} 47204431Sraj}; 48204431Sraj 49204431Srajstatic int palmas_smps_enable(struct udevice *dev, int op, bool *enable) 50204431Sraj{ 51204431Sraj int ret; 52204431Sraj unsigned int adr; 53204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 54204431Sraj 55238742Simp uc_pdata = dev_get_uclass_plat(dev); 56238742Simp adr = uc_pdata->ctrl_reg; 57238742Simp 58204431Sraj ret = pmic_reg_read(dev->parent, adr); 59204431Sraj if (ret < 0) 60204431Sraj return ret; 61204431Sraj 62204431Sraj if (op == PMIC_OP_GET) { 63204431Sraj ret &= PALMAS_SMPS_STATUS_MASK; 64204431Sraj 65204431Sraj if (ret) 66204431Sraj *enable = true; 67204431Sraj else 68204431Sraj *enable = false; 69204431Sraj 70204431Sraj return 0; 71204431Sraj } else if (op == PMIC_OP_SET) { 72204431Sraj if (*enable) 73204431Sraj ret |= PALMAS_SMPS_MODE_MASK; 74204431Sraj else 75204431Sraj ret &= ~(PALMAS_SMPS_MODE_MASK); 76204431Sraj 77204431Sraj ret = pmic_reg_write(dev->parent, adr, ret); 78204431Sraj if (ret) 79204431Sraj return ret; 80204431Sraj } 81204431Sraj 82204431Sraj return 0; 83204431Sraj} 84204431Sraj 85204431Srajstatic int palmas_smps_volt2hex(int uV) 86204431Sraj{ 87204431Sraj if (uV > PALMAS_LDO_VOLT_MAX) 88204431Sraj return -EINVAL; 89204431Sraj 90204431Sraj if (uV > 1650000) 91204431Sraj return (uV - 1000000) / 20000 + 0x6; 92238742Simp 93204431Sraj if (uV == 500000) 94204431Sraj return 0x6; 95204431Sraj else 96204431Sraj return 0x6 + ((uV - 500000) / 10000); 97238742Simp} 98204431Sraj 99204431Srajstatic int palmas_smps_hex2volt(int hex, bool range) 100204431Sraj{ 101204431Sraj unsigned int uV = 0; 102238742Simp 103204431Sraj if (hex > PALMAS_SMPS_VOLT_MAX_HEX) 104204431Sraj return -EINVAL; 105204431Sraj 106204431Sraj if (hex < 0x7) 107204431Sraj uV = 500000; 108204431Sraj else 109204431Sraj uV = 500000 + (hex - 0x6) * 10000; 110204431Sraj 111204431Sraj if (range) 112204431Sraj uV *= 2; 113204431Sraj 114204431Sraj return uV; 115204431Sraj} 116204431Sraj 117204431Srajstatic int palmas_smps_val(struct udevice *dev, int op, int *uV) 118204431Sraj{ 119204431Sraj unsigned int hex, adr; 120204431Sraj int ret; 121204431Sraj bool range; 122204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 123204431Sraj 124204431Sraj uc_pdata = dev_get_uclass_plat(dev); 125204431Sraj 126204431Sraj if (op == PMIC_OP_GET) 127204431Sraj *uV = 0; 128204431Sraj 129204431Sraj adr = uc_pdata->volt_reg; 130204433Sraj 131204433Sraj ret = pmic_reg_read(dev->parent, adr); 132204433Sraj if (ret < 0) 133204433Sraj return ret; 134204433Sraj 135204433Sraj if (op == PMIC_OP_GET) { 136204433Sraj if (ret & PALMAS_SMPS_RANGE_MASK) 137204433Sraj range = true; 138204431Sraj else 139204431Sraj range = false; 140204431Sraj 141204431Sraj ret &= PALMAS_SMPS_VOLT_MASK; 142204433Sraj ret = palmas_smps_hex2volt(ret, range); 143204433Sraj if (ret < 0) 144204433Sraj return ret; 145204431Sraj *uV = ret; 146204431Sraj 147204431Sraj return 0; 148204431Sraj } 149204431Sraj 150204431Sraj hex = palmas_smps_volt2hex(*uV); 151204431Sraj if (hex < 0) 152204431Sraj return hex; 153204431Sraj 154204431Sraj ret &= ~PALMAS_SMPS_VOLT_MASK; 155204431Sraj ret |= hex; 156204431Sraj if (*uV > 1650000) 157204431Sraj ret |= PALMAS_SMPS_RANGE_MASK; 158204431Sraj 159204431Sraj return pmic_reg_write(dev->parent, adr, ret); 160204431Sraj} 161204431Sraj 162204431Srajstatic int palmas_ldo_bypass_enable(struct udevice *dev, bool enabled) 163204431Sraj{ 164204431Sraj int type = dev_get_driver_data(dev_get_parent(dev)); 165204431Sraj struct dm_regulator_uclass_plat *p; 166204431Sraj unsigned int adr; 167204431Sraj int reg; 168204431Sraj 169204433Sraj if (type == TPS65917) { 170204431Sraj /* bypass available only on LDO1 and LDO2 */ 171204431Sraj if (dev->driver_data > 2) 172204431Sraj return -ENOTSUPP; 173204431Sraj } else if (type == TPS659038) { 174204431Sraj /* bypass available only on LDO9 */ 175204431Sraj if (dev->driver_data != 9) 176204431Sraj return -ENOTSUPP; 177204431Sraj } 178204431Sraj 179204431Sraj p = dev_get_uclass_plat(dev); 180204431Sraj adr = p->ctrl_reg; 181204431Sraj 182204433Sraj reg = pmic_reg_read(dev->parent, adr); 183204431Sraj if (reg < 0) 184204431Sraj return reg; 185204431Sraj 186204431Sraj if (enabled) 187204431Sraj reg |= PALMAS_LDO_BYPASS_EN; 188204431Sraj else 189204431Sraj reg &= ~PALMAS_LDO_BYPASS_EN; 190204431Sraj 191204431Sraj return pmic_reg_write(dev->parent, adr, reg); 192204431Sraj} 193204431Sraj 194238742Simpstatic int palmas_ldo_enable(struct udevice *dev, int op, bool *enable) 195204431Sraj{ 196204431Sraj int ret; 197238742Simp unsigned int adr; 198204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 199238742Simp 200238742Simp uc_pdata = dev_get_uclass_plat(dev); 201238742Simp adr = uc_pdata->ctrl_reg; 202204431Sraj 203204433Sraj ret = pmic_reg_read(dev->parent, adr); 204204433Sraj if (ret < 0) 205204431Sraj return ret; 206204431Sraj 207238742Simp if (op == PMIC_OP_GET) { 208204431Sraj ret &= PALMAS_LDO_STATUS_MASK; 209204431Sraj 210238742Simp if (ret) 211204431Sraj *enable = true; 212204433Sraj else 213204433Sraj *enable = false; 214238742Simp 215238742Simp return 0; 216238742Simp } else if (op == PMIC_OP_SET) { 217204431Sraj if (*enable) 218204431Sraj ret |= PALMAS_LDO_MODE_MASK; 219204431Sraj else 220238742Simp ret &= ~(PALMAS_LDO_MODE_MASK); 221204431Sraj 222204431Sraj ret = pmic_reg_write(dev->parent, adr, ret); 223238742Simp if (ret) 224204431Sraj return ret; 225238742Simp 226238742Simp ret = palmas_ldo_bypass_enable(dev, false); 227238742Simp if (ret && (ret != -ENOTSUPP)) 228204431Sraj return ret; 229204433Sraj } 230204433Sraj 231204431Sraj return 0; 232204431Sraj} 233204431Sraj 234204431Srajstatic int palmas_ldo_volt2hex(int uV) 235204431Sraj{ 236204431Sraj if (uV > PALMAS_LDO_VOLT_MAX) 237204431Sraj return -EINVAL; 238204431Sraj 239204431Sraj return (uV - 850000) / 50000; 240204431Sraj} 241204431Sraj 242204431Srajstatic int palmas_ldo_hex2volt(int hex) 243204431Sraj{ 244204431Sraj if (hex > PALMAS_LDO_VOLT_MAX_HEX) 245204431Sraj return -EINVAL; 246204431Sraj 247204431Sraj if (!hex) 248204431Sraj return 0; 249204431Sraj 250204431Sraj return (hex * 50000) + 850000; 251204431Sraj} 252204431Sraj 253204431Srajstatic int palmas_ldo_val(struct udevice *dev, int op, int *uV) 254204431Sraj{ 255204431Sraj unsigned int hex, adr; 256204431Sraj int ret; 257204431Sraj 258204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 259204431Sraj 260204431Sraj if (op == PMIC_OP_GET) 261204431Sraj *uV = 0; 262204431Sraj 263204431Sraj uc_pdata = dev_get_uclass_plat(dev); 264261215Simp 265204431Sraj adr = uc_pdata->volt_reg; 266261215Simp 267261215Simp ret = pmic_reg_read(dev->parent, adr); 268261215Simp if (ret < 0) 269238742Simp return ret; 270204431Sraj 271204431Sraj if (op == PMIC_OP_GET) { 272204431Sraj ret &= PALMAS_LDO_VOLT_MASK; 273204431Sraj ret = palmas_ldo_hex2volt(ret); 274204431Sraj if (ret < 0) 275204431Sraj return ret; 276204431Sraj *uV = ret; 277204431Sraj return 0; 278204431Sraj } 279204431Sraj 280204431Sraj hex = palmas_ldo_volt2hex(*uV); 281204431Sraj if (hex < 0) 282261215Simp return hex; 283204431Sraj 284204431Sraj ret &= ~PALMAS_LDO_VOLT_MASK; 285204431Sraj ret |= hex; 286238742Simp if (*uV > 1650000) 287204431Sraj ret |= 0x80; 288204431Sraj 289204431Sraj return pmic_reg_write(dev->parent, adr, ret); 290204431Sraj} 291204431Sraj 292204431Srajstatic int palmas_ldo_probe(struct udevice *dev) 293204431Sraj{ 294204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 295204431Sraj struct udevice *parent; 296204431Sraj 297204431Sraj uc_pdata = dev_get_uclass_plat(dev); 298204431Sraj 299204431Sraj parent = dev_get_parent(dev); 300204431Sraj int type = dev_get_driver_data(parent); 301204431Sraj 302204431Sraj uc_pdata->type = REGULATOR_TYPE_LDO; 303204431Sraj 304204431Sraj /* check for ldoln and ldousb cases */ 305204431Sraj if (!strcmp("ldoln", dev->name)) { 306204431Sraj uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9]; 307204431Sraj uc_pdata->volt_reg = palmas_ldo_volt[type][9]; 308204431Sraj return 0; 309204431Sraj } 310204431Sraj 311204431Sraj if (!strcmp("ldousb", dev->name)) { 312204431Sraj uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10]; 313238742Simp uc_pdata->volt_reg = palmas_ldo_volt[type][10]; 314204431Sraj return 0; 315204431Sraj } 316204431Sraj 317204431Sraj if (dev->driver_data > 0) { 318204431Sraj u8 idx = dev->driver_data - 1; 319204431Sraj uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx]; 320204431Sraj uc_pdata->volt_reg = palmas_ldo_volt[type][idx]; 321204431Sraj } 322204431Sraj 323204431Sraj return 0; 324204431Sraj} 325204431Sraj 326204431Srajstatic int ldo_get_value(struct udevice *dev) 327204431Sraj{ 328204431Sraj int uV; 329204431Sraj int ret; 330204431Sraj 331204431Sraj ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV); 332204431Sraj if (ret) 333204431Sraj return ret; 334204431Sraj 335204431Sraj return uV; 336204431Sraj} 337204431Sraj 338204431Srajstatic int ldo_set_value(struct udevice *dev, int uV) 339204431Sraj{ 340204431Sraj return palmas_ldo_val(dev, PMIC_OP_SET, &uV); 341204431Sraj} 342204431Sraj 343204431Srajstatic int ldo_get_enable(struct udevice *dev) 344204431Sraj{ 345204431Sraj bool enable = false; 346204431Sraj int ret; 347204431Sraj 348204431Sraj ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable); 349204431Sraj if (ret) 350204431Sraj return ret; 351204431Sraj 352204431Sraj return enable; 353204431Sraj} 354204431Sraj 355204431Srajstatic int ldo_set_enable(struct udevice *dev, bool enable) 356204431Sraj{ 357204431Sraj return palmas_ldo_enable(dev, PMIC_OP_SET, &enable); 358204431Sraj} 359204431Sraj 360204431Srajstatic int palmas_smps_probe(struct udevice *dev) 361204431Sraj{ 362204431Sraj struct dm_regulator_uclass_plat *uc_pdata; 363204431Sraj struct udevice *parent; 364204431Sraj int idx; 365204431Sraj 366204431Sraj uc_pdata = dev_get_uclass_plat(dev); 367204431Sraj 368204431Sraj parent = dev_get_parent(dev); 369204431Sraj int type = dev_get_driver_data(parent); 370204431Sraj 371204431Sraj uc_pdata->type = REGULATOR_TYPE_BUCK; 372204431Sraj 373204431Sraj switch (type) { 374204431Sraj case PALMAS: 375204431Sraj case TPS659038: 376204431Sraj switch (dev->driver_data) { 377204431Sraj case 123: 378204431Sraj case 12: 379204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0]; 380204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][0]; 381204431Sraj break; 382204431Sraj case 3: 383204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1]; 384204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][1]; 385204431Sraj break; 386204431Sraj case 45: 387204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2]; 388204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][2]; 389204431Sraj break; 390204431Sraj case 6: 391204431Sraj case 7: 392204431Sraj case 8: 393204431Sraj case 9: 394204431Sraj case 10: 395204431Sraj idx = dev->driver_data - 3; 396204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx]; 397204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][idx]; 398204431Sraj break; 399204431Sraj 400204431Sraj default: 401204431Sraj printf("Wrong ID for regulator\n"); 402204431Sraj } 403204431Sraj break; 404204431Sraj 405204431Sraj case TPS65917: 406204431Sraj switch (dev->driver_data) { 407204431Sraj case 1: 408204431Sraj case 2: 409204431Sraj case 3: 410204431Sraj case 4: 411204431Sraj case 5: 412204431Sraj idx = dev->driver_data - 1; 413204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx]; 414204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][idx]; 415204431Sraj break; 416204431Sraj case 12: 417204431Sraj idx = 0; 418204431Sraj uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx]; 419204431Sraj uc_pdata->volt_reg = palmas_smps_volt[type][idx]; 420204431Sraj break; 421204431Sraj default: 422204431Sraj printf("Wrong ID for regulator\n"); 423204431Sraj } 424204431Sraj break; 425204431Sraj 426204431Sraj default: 427204431Sraj printf("Invalid PMIC ID\n"); 428204431Sraj } 429204431Sraj 430204431Sraj return 0; 431204431Sraj} 432204431Sraj 433204431Srajstatic int smps_get_value(struct udevice *dev) 434204433Sraj{ 435204433Sraj int uV; 436204433Sraj int ret; 437204433Sraj 438204433Sraj ret = palmas_smps_val(dev, PMIC_OP_GET, &uV); 439204433Sraj if (ret) 440204433Sraj return ret; 441204431Sraj 442204431Sraj return uV; 443204431Sraj} 444204431Sraj 445204431Srajstatic int smps_set_value(struct udevice *dev, int uV) 446204431Sraj{ 447204431Sraj return palmas_smps_val(dev, PMIC_OP_SET, &uV); 448204431Sraj} 449204431Sraj 450204431Srajstatic int smps_get_enable(struct udevice *dev) 451204431Sraj{ 452204431Sraj bool enable = false; 453204431Sraj int ret; 454204431Sraj 455204431Sraj ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable); 456204431Sraj if (ret) 457204431Sraj return ret; 458204431Sraj 459204431Sraj return enable; 460204431Sraj} 461204431Sraj 462204431Srajstatic int smps_set_enable(struct udevice *dev, bool enable) 463204431Sraj{ 464204431Sraj return palmas_smps_enable(dev, PMIC_OP_SET, &enable); 465204431Sraj} 466204431Sraj 467204431Srajstatic const struct dm_regulator_ops palmas_ldo_ops = { 468204431Sraj .get_value = ldo_get_value, 469204431Sraj .set_value = ldo_set_value, 470204431Sraj .get_enable = ldo_get_enable, 471204431Sraj .set_enable = ldo_set_enable, 472204431Sraj}; 473204431Sraj 474204431SrajU_BOOT_DRIVER(palmas_ldo) = { 475204431Sraj .name = PALMAS_LDO_DRIVER, 476204431Sraj .id = UCLASS_REGULATOR, 477204431Sraj .ops = &palmas_ldo_ops, 478204431Sraj .probe = palmas_ldo_probe, 479204431Sraj}; 480204431Sraj 481204431Srajstatic const struct dm_regulator_ops palmas_smps_ops = { 482204433Sraj .get_value = smps_get_value, 483204433Sraj .set_value = smps_set_value, 484204433Sraj .get_enable = smps_get_enable, 485204433Sraj .set_enable = smps_set_enable, 486204433Sraj}; 487204433Sraj 488204433SrajU_BOOT_DRIVER(palmas_smps) = { 489204431Sraj .name = PALMAS_SMPS_DRIVER, 490204433Sraj .id = UCLASS_REGULATOR, 491204433Sraj .ops = &palmas_smps_ops, 492204431Sraj .probe = palmas_smps_probe, 493204433Sraj}; 494204433Sraj