1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22dd9dc02SKeerthy /*
32dd9dc02SKeerthy * (C) Copyright 2017
42dd9dc02SKeerthy * Texas Instruments Incorporated, <www.ti.com>
52dd9dc02SKeerthy *
62dd9dc02SKeerthy * Keerthy <j-keerthy@ti.com>
72dd9dc02SKeerthy */
82dd9dc02SKeerthy
92dd9dc02SKeerthy #include <common.h>
102dd9dc02SKeerthy #include <fdtdec.h>
112dd9dc02SKeerthy #include <errno.h>
122dd9dc02SKeerthy #include <dm.h>
132dd9dc02SKeerthy #include <i2c.h>
142dd9dc02SKeerthy #include <power/pmic.h>
152dd9dc02SKeerthy #include <power/regulator.h>
162dd9dc02SKeerthy #include <power/lp87565.h>
172dd9dc02SKeerthy
182dd9dc02SKeerthy static const char lp87565_buck_ctrl1[LP87565_BUCK_NUM] = {0x2, 0x4, 0x6, 0x8, 0x2, 0x6};
192dd9dc02SKeerthy static const char lp87565_buck_vout[LP87565_BUCK_NUM] = {0xA, 0xC, 0xE, 0x10, 0xA, 0xE };
202dd9dc02SKeerthy
lp87565_buck_enable(struct udevice * dev,int op,bool * enable)212dd9dc02SKeerthy static int lp87565_buck_enable(struct udevice *dev, int op, bool *enable)
222dd9dc02SKeerthy {
232dd9dc02SKeerthy int ret;
242dd9dc02SKeerthy unsigned int adr;
252dd9dc02SKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
262dd9dc02SKeerthy
272dd9dc02SKeerthy uc_pdata = dev_get_uclass_platdata(dev);
282dd9dc02SKeerthy adr = uc_pdata->ctrl_reg;
292dd9dc02SKeerthy
302dd9dc02SKeerthy ret = pmic_reg_read(dev->parent, adr);
312dd9dc02SKeerthy if (ret < 0)
322dd9dc02SKeerthy return ret;
332dd9dc02SKeerthy
342dd9dc02SKeerthy if (op == PMIC_OP_GET) {
352dd9dc02SKeerthy ret &= LP87565_BUCK_MODE_MASK;
362dd9dc02SKeerthy
372dd9dc02SKeerthy if (ret)
382dd9dc02SKeerthy *enable = true;
392dd9dc02SKeerthy else
402dd9dc02SKeerthy *enable = false;
412dd9dc02SKeerthy
422dd9dc02SKeerthy return 0;
432dd9dc02SKeerthy } else if (op == PMIC_OP_SET) {
442dd9dc02SKeerthy if (*enable)
452dd9dc02SKeerthy ret |= LP87565_BUCK_MODE_MASK;
462dd9dc02SKeerthy else
472dd9dc02SKeerthy ret &= ~LP87565_BUCK_MODE_MASK;
482dd9dc02SKeerthy ret = pmic_reg_write(dev->parent, adr, ret);
492dd9dc02SKeerthy if (ret)
502dd9dc02SKeerthy return ret;
512dd9dc02SKeerthy }
522dd9dc02SKeerthy
532dd9dc02SKeerthy return 0;
542dd9dc02SKeerthy }
552dd9dc02SKeerthy
lp87565_buck_volt2val(int uV)562dd9dc02SKeerthy static int lp87565_buck_volt2val(int uV)
572dd9dc02SKeerthy {
582dd9dc02SKeerthy if (uV > LP87565_BUCK_VOLT_MAX)
592dd9dc02SKeerthy return -EINVAL;
602dd9dc02SKeerthy else if (uV > 1400000)
612dd9dc02SKeerthy return (uV - 1420000) / 20000 + 0x9E;
622dd9dc02SKeerthy else if (uV > 730000)
632dd9dc02SKeerthy return (uV - 735000) / 5000 + 0x18;
642dd9dc02SKeerthy else if (uV >= 500000)
652dd9dc02SKeerthy return (uV - 500000) / 10000;
662dd9dc02SKeerthy else
672dd9dc02SKeerthy return -EINVAL;
682dd9dc02SKeerthy }
692dd9dc02SKeerthy
lp87565_buck_val2volt(int val)702dd9dc02SKeerthy static int lp87565_buck_val2volt(int val)
712dd9dc02SKeerthy {
722dd9dc02SKeerthy if (val > LP87565_BUCK_VOLT_MAX_HEX)
732dd9dc02SKeerthy return -EINVAL;
742dd9dc02SKeerthy else if (val > 0x9D)
752dd9dc02SKeerthy return 1400000 + (val - 0x9D) * 20000;
762dd9dc02SKeerthy else if (val > 0x17)
772dd9dc02SKeerthy return 730000 + (val - 0x17) * 5000;
782dd9dc02SKeerthy else if (val >= 0x0)
792dd9dc02SKeerthy return 500000 + val * 10000;
802dd9dc02SKeerthy else
812dd9dc02SKeerthy return -EINVAL;
822dd9dc02SKeerthy }
832dd9dc02SKeerthy
lp87565_buck_val(struct udevice * dev,int op,int * uV)842dd9dc02SKeerthy static int lp87565_buck_val(struct udevice *dev, int op, int *uV)
852dd9dc02SKeerthy {
862dd9dc02SKeerthy unsigned int hex, adr;
872dd9dc02SKeerthy int ret;
882dd9dc02SKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
892dd9dc02SKeerthy
902dd9dc02SKeerthy uc_pdata = dev_get_uclass_platdata(dev);
912dd9dc02SKeerthy
922dd9dc02SKeerthy if (op == PMIC_OP_GET)
932dd9dc02SKeerthy *uV = 0;
942dd9dc02SKeerthy
952dd9dc02SKeerthy adr = uc_pdata->volt_reg;
962dd9dc02SKeerthy
972dd9dc02SKeerthy ret = pmic_reg_read(dev->parent, adr);
982dd9dc02SKeerthy if (ret < 0)
992dd9dc02SKeerthy return ret;
1002dd9dc02SKeerthy
1012dd9dc02SKeerthy if (op == PMIC_OP_GET) {
1022dd9dc02SKeerthy ret &= LP87565_BUCK_VOLT_MASK;
1032dd9dc02SKeerthy ret = lp87565_buck_val2volt(ret);
1042dd9dc02SKeerthy if (ret < 0)
1052dd9dc02SKeerthy return ret;
1062dd9dc02SKeerthy *uV = ret;
1072dd9dc02SKeerthy
1082dd9dc02SKeerthy return 0;
1092dd9dc02SKeerthy }
1102dd9dc02SKeerthy
1112dd9dc02SKeerthy hex = lp87565_buck_volt2val(*uV);
1122dd9dc02SKeerthy if (hex < 0)
1132dd9dc02SKeerthy return hex;
1142dd9dc02SKeerthy
1152dd9dc02SKeerthy ret &= 0x0;
1162dd9dc02SKeerthy ret = hex;
1172dd9dc02SKeerthy
1182dd9dc02SKeerthy ret = pmic_reg_write(dev->parent, adr, ret);
1192dd9dc02SKeerthy
1202dd9dc02SKeerthy return ret;
1212dd9dc02SKeerthy }
1222dd9dc02SKeerthy
lp87565_buck_probe(struct udevice * dev)1232dd9dc02SKeerthy static int lp87565_buck_probe(struct udevice *dev)
1242dd9dc02SKeerthy {
1252dd9dc02SKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
1262dd9dc02SKeerthy int idx;
1272dd9dc02SKeerthy
1282dd9dc02SKeerthy uc_pdata = dev_get_uclass_platdata(dev);
1292dd9dc02SKeerthy uc_pdata->type = REGULATOR_TYPE_BUCK;
1302dd9dc02SKeerthy
1312dd9dc02SKeerthy idx = dev->driver_data;
1322dd9dc02SKeerthy if (idx == 0 || idx == 1 || idx == 2 || idx == 3) {
1332dd9dc02SKeerthy debug("Single phase regulator\n");
1342dd9dc02SKeerthy } else if (idx == 23) {
1352dd9dc02SKeerthy idx = 5;
1362dd9dc02SKeerthy } else if (idx == 10) {
1372dd9dc02SKeerthy idx = 4;
1382dd9dc02SKeerthy } else {
1392dd9dc02SKeerthy printf("Wrong ID for regulator\n");
1402dd9dc02SKeerthy return -EINVAL;
1412dd9dc02SKeerthy }
1422dd9dc02SKeerthy
1432dd9dc02SKeerthy uc_pdata->ctrl_reg = lp87565_buck_ctrl1[idx];
1442dd9dc02SKeerthy uc_pdata->volt_reg = lp87565_buck_vout[idx];
1452dd9dc02SKeerthy
1462dd9dc02SKeerthy return 0;
1472dd9dc02SKeerthy }
1482dd9dc02SKeerthy
buck_get_value(struct udevice * dev)1492dd9dc02SKeerthy static int buck_get_value(struct udevice *dev)
1502dd9dc02SKeerthy {
1512dd9dc02SKeerthy int uV;
1522dd9dc02SKeerthy int ret;
1532dd9dc02SKeerthy
1542dd9dc02SKeerthy ret = lp87565_buck_val(dev, PMIC_OP_GET, &uV);
1552dd9dc02SKeerthy if (ret)
1562dd9dc02SKeerthy return ret;
1572dd9dc02SKeerthy
1582dd9dc02SKeerthy return uV;
1592dd9dc02SKeerthy }
1602dd9dc02SKeerthy
buck_set_value(struct udevice * dev,int uV)1612dd9dc02SKeerthy static int buck_set_value(struct udevice *dev, int uV)
1622dd9dc02SKeerthy {
1632dd9dc02SKeerthy return lp87565_buck_val(dev, PMIC_OP_SET, &uV);
1642dd9dc02SKeerthy }
1652dd9dc02SKeerthy
buck_get_enable(struct udevice * dev)166a79e8dfeSKeerthy static int buck_get_enable(struct udevice *dev)
1672dd9dc02SKeerthy {
1682dd9dc02SKeerthy bool enable = false;
1692dd9dc02SKeerthy int ret;
1702dd9dc02SKeerthy
1712dd9dc02SKeerthy
1722dd9dc02SKeerthy ret = lp87565_buck_enable(dev, PMIC_OP_GET, &enable);
1732dd9dc02SKeerthy if (ret)
1742dd9dc02SKeerthy return ret;
1752dd9dc02SKeerthy
1762dd9dc02SKeerthy return enable;
1772dd9dc02SKeerthy }
1782dd9dc02SKeerthy
buck_set_enable(struct udevice * dev,bool enable)1792dd9dc02SKeerthy static int buck_set_enable(struct udevice *dev, bool enable)
1802dd9dc02SKeerthy {
1812dd9dc02SKeerthy return lp87565_buck_enable(dev, PMIC_OP_SET, &enable);
1822dd9dc02SKeerthy }
1832dd9dc02SKeerthy
1842dd9dc02SKeerthy static const struct dm_regulator_ops lp87565_buck_ops = {
1852dd9dc02SKeerthy .get_value = buck_get_value,
1862dd9dc02SKeerthy .set_value = buck_set_value,
1872dd9dc02SKeerthy .get_enable = buck_get_enable,
1882dd9dc02SKeerthy .set_enable = buck_set_enable,
1892dd9dc02SKeerthy };
1902dd9dc02SKeerthy
1912dd9dc02SKeerthy U_BOOT_DRIVER(lp87565_buck) = {
1922dd9dc02SKeerthy .name = LP87565_BUCK_DRIVER,
1932dd9dc02SKeerthy .id = UCLASS_REGULATOR,
1942dd9dc02SKeerthy .ops = &lp87565_buck_ops,
1952dd9dc02SKeerthy .probe = lp87565_buck_probe,
1962dd9dc02SKeerthy };
197