xref: /rk3399_rockchip-uboot/drivers/power/regulator/lp873x_regulator.c (revision 43d0247e3ef8e2f6551026d298dea84d9c7fb2d7)
199785de8SKeerthy /*
299785de8SKeerthy  * (C) Copyright 2016
399785de8SKeerthy  * Texas Instruments Incorporated, <www.ti.com>
499785de8SKeerthy  *
599785de8SKeerthy  * Keerthy <j-keerthy@ti.com>
699785de8SKeerthy  *
799785de8SKeerthy  * SPDX-License-Identifier:	GPL-2.0+
899785de8SKeerthy  */
999785de8SKeerthy 
1099785de8SKeerthy #include <common.h>
1199785de8SKeerthy #include <fdtdec.h>
1299785de8SKeerthy #include <errno.h>
1399785de8SKeerthy #include <dm.h>
1499785de8SKeerthy #include <i2c.h>
1599785de8SKeerthy #include <power/pmic.h>
1699785de8SKeerthy #include <power/regulator.h>
1799785de8SKeerthy #include <power/lp873x.h>
1899785de8SKeerthy 
1999785de8SKeerthy DECLARE_GLOBAL_DATA_PTR;
2099785de8SKeerthy 
2199785de8SKeerthy static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4};
2299785de8SKeerthy static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7};
2399785de8SKeerthy static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9};
2499785de8SKeerthy static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB};
2599785de8SKeerthy 
lp873x_buck_enable(struct udevice * dev,int op,bool * enable)2699785de8SKeerthy static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable)
2799785de8SKeerthy {
2899785de8SKeerthy 	int ret;
2999785de8SKeerthy 	unsigned int adr;
3099785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
3199785de8SKeerthy 
3299785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
3399785de8SKeerthy 	adr = uc_pdata->ctrl_reg;
3499785de8SKeerthy 
3599785de8SKeerthy 	ret = pmic_reg_read(dev->parent, adr);
3699785de8SKeerthy 	if (ret < 0)
3799785de8SKeerthy 		return ret;
3899785de8SKeerthy 
3999785de8SKeerthy 	if (op == PMIC_OP_GET) {
4099785de8SKeerthy 		ret &= LP873X_BUCK_MODE_MASK;
4199785de8SKeerthy 
4299785de8SKeerthy 		if (ret)
4399785de8SKeerthy 			*enable = true;
4499785de8SKeerthy 		else
4599785de8SKeerthy 			*enable = false;
4699785de8SKeerthy 
4799785de8SKeerthy 		return 0;
4899785de8SKeerthy 	} else if (op == PMIC_OP_SET) {
4999785de8SKeerthy 		if (*enable)
5099785de8SKeerthy 			ret |= LP873X_BUCK_MODE_MASK;
5199785de8SKeerthy 		else
5299785de8SKeerthy 			ret &= ~(LP873X_BUCK_MODE_MASK);
5399785de8SKeerthy 		ret = pmic_reg_write(dev->parent, adr, ret);
5499785de8SKeerthy 		if (ret)
5599785de8SKeerthy 			return ret;
5699785de8SKeerthy 	}
5799785de8SKeerthy 
5899785de8SKeerthy 	return 0;
5999785de8SKeerthy }
6099785de8SKeerthy 
lp873x_buck_volt2hex(int uV)6199785de8SKeerthy static int lp873x_buck_volt2hex(int uV)
6299785de8SKeerthy {
6399785de8SKeerthy 	if (uV > LP873X_BUCK_VOLT_MAX)
6499785de8SKeerthy 		return -EINVAL;
6599785de8SKeerthy 	else if (uV > 1400000)
6699785de8SKeerthy 		return (uV - 1420000) / 20000 + 0x9E;
6799785de8SKeerthy 	else if (uV > 730000)
6899785de8SKeerthy 		return (uV - 735000) / 5000 + 0x18;
6999785de8SKeerthy 	else if (uV >= 700000)
7099785de8SKeerthy 		return (uV - 700000) / 10000 + 0x1;
7199785de8SKeerthy 	else
7299785de8SKeerthy 		return -EINVAL;
7399785de8SKeerthy }
7499785de8SKeerthy 
lp873x_buck_hex2volt(int hex)7599785de8SKeerthy static int lp873x_buck_hex2volt(int hex)
7699785de8SKeerthy {
7799785de8SKeerthy 	if (hex > LP873X_BUCK_VOLT_MAX_HEX)
7899785de8SKeerthy 		return -EINVAL;
7999785de8SKeerthy 	else if (hex > 0x9D)
8099785de8SKeerthy 		return 1400000 + (hex - 0x9D) * 20000;
8199785de8SKeerthy 	else if (hex > 0x17)
8299785de8SKeerthy 		return 730000 + (hex - 0x17) * 5000;
8399785de8SKeerthy 	else if (hex >= 0x14)
8499785de8SKeerthy 		return 700000 + (hex - 0x14) * 10000;
8599785de8SKeerthy 	else
8699785de8SKeerthy 		return -EINVAL;
8799785de8SKeerthy }
8899785de8SKeerthy 
lp873x_buck_val(struct udevice * dev,int op,int * uV)8999785de8SKeerthy static int lp873x_buck_val(struct udevice *dev, int op, int *uV)
9099785de8SKeerthy {
9199785de8SKeerthy 	unsigned int hex, adr;
9299785de8SKeerthy 	int ret;
9399785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
9499785de8SKeerthy 
9599785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
9699785de8SKeerthy 
9799785de8SKeerthy 	if (op == PMIC_OP_GET)
9899785de8SKeerthy 		*uV = 0;
9999785de8SKeerthy 
10099785de8SKeerthy 	adr = uc_pdata->volt_reg;
10199785de8SKeerthy 
10299785de8SKeerthy 	ret = pmic_reg_read(dev->parent, adr);
10399785de8SKeerthy 	if (ret < 0)
10499785de8SKeerthy 		return ret;
10599785de8SKeerthy 
10699785de8SKeerthy 	if (op == PMIC_OP_GET) {
10799785de8SKeerthy 		ret &= LP873X_BUCK_VOLT_MASK;
10899785de8SKeerthy 		ret = lp873x_buck_hex2volt(ret);
10999785de8SKeerthy 		if (ret < 0)
11099785de8SKeerthy 			return ret;
11199785de8SKeerthy 		*uV = ret;
11299785de8SKeerthy 
11399785de8SKeerthy 		return 0;
11499785de8SKeerthy 	}
11599785de8SKeerthy 
11699785de8SKeerthy 	hex = lp873x_buck_volt2hex(*uV);
11799785de8SKeerthy 	if (hex < 0)
11899785de8SKeerthy 		return hex;
11999785de8SKeerthy 
12099785de8SKeerthy 	ret &= 0x0;
12199785de8SKeerthy 	ret |= hex;
12299785de8SKeerthy 
12399785de8SKeerthy 	ret = pmic_reg_write(dev->parent, adr, ret);
12499785de8SKeerthy 
12599785de8SKeerthy 	return ret;
12699785de8SKeerthy }
12799785de8SKeerthy 
lp873x_ldo_enable(struct udevice * dev,int op,bool * enable)12899785de8SKeerthy static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable)
12999785de8SKeerthy {
13099785de8SKeerthy 	int ret;
13199785de8SKeerthy 	unsigned int adr;
13299785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
13399785de8SKeerthy 
13499785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
13599785de8SKeerthy 	adr = uc_pdata->ctrl_reg;
13699785de8SKeerthy 
13799785de8SKeerthy 	ret = pmic_reg_read(dev->parent, adr);
13899785de8SKeerthy 	if (ret < 0)
13999785de8SKeerthy 		return ret;
14099785de8SKeerthy 
14199785de8SKeerthy 	if (op == PMIC_OP_GET) {
14299785de8SKeerthy 		ret &= LP873X_LDO_MODE_MASK;
14399785de8SKeerthy 
14499785de8SKeerthy 		if (ret)
14599785de8SKeerthy 			*enable = true;
14699785de8SKeerthy 		else
14799785de8SKeerthy 			*enable = false;
14899785de8SKeerthy 
14999785de8SKeerthy 		return 0;
15099785de8SKeerthy 	} else if (op == PMIC_OP_SET) {
15199785de8SKeerthy 		if (*enable)
15299785de8SKeerthy 			ret |= LP873X_LDO_MODE_MASK;
15399785de8SKeerthy 		else
15499785de8SKeerthy 			ret &= ~(LP873X_LDO_MODE_MASK);
15599785de8SKeerthy 
15699785de8SKeerthy 		ret = pmic_reg_write(dev->parent, adr, ret);
15799785de8SKeerthy 		if (ret)
15899785de8SKeerthy 			return ret;
15999785de8SKeerthy 	}
16099785de8SKeerthy 
16199785de8SKeerthy 	return 0;
16299785de8SKeerthy }
16399785de8SKeerthy 
lp873x_ldo_volt2hex(int uV)16499785de8SKeerthy static int lp873x_ldo_volt2hex(int uV)
16599785de8SKeerthy {
16699785de8SKeerthy 	if (uV > LP873X_LDO_VOLT_MAX)
16799785de8SKeerthy 		return -EINVAL;
16899785de8SKeerthy 
16999785de8SKeerthy 	return (uV - 800000) / 100000;
17099785de8SKeerthy }
17199785de8SKeerthy 
lp873x_ldo_hex2volt(int hex)17299785de8SKeerthy static int lp873x_ldo_hex2volt(int hex)
17399785de8SKeerthy {
17499785de8SKeerthy 	if (hex > LP873X_LDO_VOLT_MAX_HEX)
17599785de8SKeerthy 		return -EINVAL;
17699785de8SKeerthy 
17799785de8SKeerthy 	if (!hex)
17899785de8SKeerthy 		return 0;
17999785de8SKeerthy 
18099785de8SKeerthy 	return (hex * 100000) + 800000;
18199785de8SKeerthy }
18299785de8SKeerthy 
lp873x_ldo_val(struct udevice * dev,int op,int * uV)18399785de8SKeerthy static int lp873x_ldo_val(struct udevice *dev, int op, int *uV)
18499785de8SKeerthy {
18599785de8SKeerthy 	unsigned int hex, adr;
18699785de8SKeerthy 	int ret;
18799785de8SKeerthy 
18899785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
18999785de8SKeerthy 
19099785de8SKeerthy 	if (op == PMIC_OP_GET)
19199785de8SKeerthy 		*uV = 0;
19299785de8SKeerthy 
19399785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
19499785de8SKeerthy 
19599785de8SKeerthy 	adr = uc_pdata->volt_reg;
19699785de8SKeerthy 
19799785de8SKeerthy 	ret = pmic_reg_read(dev->parent, adr);
19899785de8SKeerthy 	if (ret < 0)
19999785de8SKeerthy 		return ret;
20099785de8SKeerthy 
20199785de8SKeerthy 	if (op == PMIC_OP_GET) {
20299785de8SKeerthy 		ret &= LP873X_LDO_VOLT_MASK;
20399785de8SKeerthy 		ret = lp873x_ldo_hex2volt(ret);
20499785de8SKeerthy 		if (ret < 0)
20599785de8SKeerthy 			return ret;
20699785de8SKeerthy 		*uV = ret;
20799785de8SKeerthy 		return 0;
20899785de8SKeerthy 	}
20999785de8SKeerthy 
21099785de8SKeerthy 	hex = lp873x_ldo_volt2hex(*uV);
21199785de8SKeerthy 	if (hex < 0)
21299785de8SKeerthy 		return hex;
21399785de8SKeerthy 
21499785de8SKeerthy 	ret &= ~LP873X_LDO_VOLT_MASK;
21599785de8SKeerthy 	ret |= hex;
21699785de8SKeerthy 	if (*uV > 1650000)
21799785de8SKeerthy 		ret |= 0x80;
21899785de8SKeerthy 	ret = pmic_reg_write(dev->parent, adr, ret);
21999785de8SKeerthy 
22099785de8SKeerthy 	return ret;
22199785de8SKeerthy }
22299785de8SKeerthy 
lp873x_ldo_probe(struct udevice * dev)22399785de8SKeerthy static int lp873x_ldo_probe(struct udevice *dev)
22499785de8SKeerthy {
22599785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
22699785de8SKeerthy 
22799785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
22899785de8SKeerthy 	uc_pdata->type = REGULATOR_TYPE_LDO;
22999785de8SKeerthy 
23099785de8SKeerthy 	int idx = dev->driver_data;
23199785de8SKeerthy 	if (idx >= LP873X_LDO_NUM) {
23299785de8SKeerthy 		printf("Wrong ID for regulator\n");
23399785de8SKeerthy 		return -1;
23499785de8SKeerthy 	}
23599785de8SKeerthy 
23699785de8SKeerthy 	uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx];
23799785de8SKeerthy 	uc_pdata->volt_reg = lp873x_ldo_volt[idx];
23899785de8SKeerthy 
23999785de8SKeerthy 	return 0;
24099785de8SKeerthy }
24199785de8SKeerthy 
ldo_get_value(struct udevice * dev)24299785de8SKeerthy static int ldo_get_value(struct udevice *dev)
24399785de8SKeerthy {
24499785de8SKeerthy 	int uV;
24599785de8SKeerthy 	int ret;
24699785de8SKeerthy 
24799785de8SKeerthy 	ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV);
24899785de8SKeerthy 	if (ret)
24999785de8SKeerthy 		return ret;
25099785de8SKeerthy 
25199785de8SKeerthy 	return uV;
25299785de8SKeerthy }
25399785de8SKeerthy 
ldo_set_value(struct udevice * dev,int uV)25499785de8SKeerthy static int ldo_set_value(struct udevice *dev, int uV)
25599785de8SKeerthy {
25699785de8SKeerthy 	return lp873x_ldo_val(dev, PMIC_OP_SET, &uV);
25799785de8SKeerthy }
25899785de8SKeerthy 
ldo_get_enable(struct udevice * dev)259*43d0247eSKeerthy static int ldo_get_enable(struct udevice *dev)
26099785de8SKeerthy {
26199785de8SKeerthy 	bool enable = false;
26299785de8SKeerthy 	int ret;
26399785de8SKeerthy 
26499785de8SKeerthy 	ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable);
26599785de8SKeerthy 	if (ret)
26699785de8SKeerthy 		return ret;
26799785de8SKeerthy 
26899785de8SKeerthy 	return enable;
26999785de8SKeerthy }
27099785de8SKeerthy 
ldo_set_enable(struct udevice * dev,bool enable)27199785de8SKeerthy static int ldo_set_enable(struct udevice *dev, bool enable)
27299785de8SKeerthy {
27399785de8SKeerthy 	return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable);
27499785de8SKeerthy }
27599785de8SKeerthy 
lp873x_buck_probe(struct udevice * dev)27699785de8SKeerthy static int lp873x_buck_probe(struct udevice *dev)
27799785de8SKeerthy {
27899785de8SKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
27999785de8SKeerthy 	int idx;
28099785de8SKeerthy 
28199785de8SKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
28299785de8SKeerthy 	uc_pdata->type = REGULATOR_TYPE_BUCK;
28399785de8SKeerthy 
28499785de8SKeerthy 	idx = dev->driver_data;
28599785de8SKeerthy 	if (idx >= LP873X_BUCK_NUM) {
28699785de8SKeerthy 		printf("Wrong ID for regulator\n");
28799785de8SKeerthy 		return -1;
28899785de8SKeerthy 	}
28999785de8SKeerthy 
29099785de8SKeerthy 	uc_pdata->ctrl_reg = lp873x_buck_ctrl[idx];
29199785de8SKeerthy 	uc_pdata->volt_reg = lp873x_buck_volt[idx];
29299785de8SKeerthy 
29399785de8SKeerthy 	return 0;
29499785de8SKeerthy }
29599785de8SKeerthy 
buck_get_value(struct udevice * dev)29699785de8SKeerthy static int buck_get_value(struct udevice *dev)
29799785de8SKeerthy {
29899785de8SKeerthy 	int uV;
29999785de8SKeerthy 	int ret;
30099785de8SKeerthy 
30199785de8SKeerthy 	ret = lp873x_buck_val(dev, PMIC_OP_GET, &uV);
30299785de8SKeerthy 	if (ret)
30399785de8SKeerthy 		return ret;
30499785de8SKeerthy 
30599785de8SKeerthy 	return uV;
30699785de8SKeerthy }
30799785de8SKeerthy 
buck_set_value(struct udevice * dev,int uV)30899785de8SKeerthy static int buck_set_value(struct udevice *dev, int uV)
30999785de8SKeerthy {
31099785de8SKeerthy 	return lp873x_buck_val(dev, PMIC_OP_SET, &uV);
31199785de8SKeerthy }
31299785de8SKeerthy 
buck_get_enable(struct udevice * dev)313*43d0247eSKeerthy static int buck_get_enable(struct udevice *dev)
31499785de8SKeerthy {
31599785de8SKeerthy 	bool enable = false;
31699785de8SKeerthy 	int ret;
31799785de8SKeerthy 
31899785de8SKeerthy 
31999785de8SKeerthy 	ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable);
32099785de8SKeerthy 	if (ret)
32199785de8SKeerthy 		return ret;
32299785de8SKeerthy 
32399785de8SKeerthy 	return enable;
32499785de8SKeerthy }
32599785de8SKeerthy 
buck_set_enable(struct udevice * dev,bool enable)32699785de8SKeerthy static int buck_set_enable(struct udevice *dev, bool enable)
32799785de8SKeerthy {
32899785de8SKeerthy 	return lp873x_buck_enable(dev, PMIC_OP_SET, &enable);
32999785de8SKeerthy }
33099785de8SKeerthy 
33199785de8SKeerthy static const struct dm_regulator_ops lp873x_ldo_ops = {
33299785de8SKeerthy 	.get_value  = ldo_get_value,
33399785de8SKeerthy 	.set_value  = ldo_set_value,
33499785de8SKeerthy 	.get_enable = ldo_get_enable,
33599785de8SKeerthy 	.set_enable = ldo_set_enable,
33699785de8SKeerthy };
33799785de8SKeerthy 
33899785de8SKeerthy U_BOOT_DRIVER(lp873x_ldo) = {
33999785de8SKeerthy 	.name = LP873X_LDO_DRIVER,
34099785de8SKeerthy 	.id = UCLASS_REGULATOR,
34199785de8SKeerthy 	.ops = &lp873x_ldo_ops,
34299785de8SKeerthy 	.probe = lp873x_ldo_probe,
34399785de8SKeerthy };
34499785de8SKeerthy 
34599785de8SKeerthy static const struct dm_regulator_ops lp873x_buck_ops = {
34699785de8SKeerthy 	.get_value  = buck_get_value,
34799785de8SKeerthy 	.set_value  = buck_set_value,
34899785de8SKeerthy 	.get_enable = buck_get_enable,
34999785de8SKeerthy 	.set_enable = buck_set_enable,
35099785de8SKeerthy };
35199785de8SKeerthy 
35299785de8SKeerthy U_BOOT_DRIVER(lp873x_buck) = {
35399785de8SKeerthy 	.name = LP873X_BUCK_DRIVER,
35499785de8SKeerthy 	.id = UCLASS_REGULATOR,
35599785de8SKeerthy 	.ops = &lp873x_buck_ops,
35699785de8SKeerthy 	.probe = lp873x_buck_probe,
35799785de8SKeerthy };
358