summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorJoseph Chen <chenjh@rock-chips.com>2019-09-26 15:44:55 +0800
committerKever Yang <kever.yang@rock-chips.com>2019-11-10 20:33:52 +0800
commitb4a35574b38d0fb42031be32a47fb1095cceafa7 (patch)
treead4f14d38c6b465df0eaa9d05c50ce5315aba1dc /drivers/power
parentb62280745e553b5800fa0797b920e547c92da82d (diff)
power: pmic: rk817: support rk817 pmic
The RK817 is a Power Management IC (PMIC) for multimedia and handheld devices. They contains the following components: - Regulators(4*BUCKs, 1* BOOST, 9*LDOs, 1*SWITCH) - RTC - Clocking Signed-off-by: Joseph Chen <chenjh@rock-chips.com> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com> Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/pmic/rk8xx.c84
-rw-r--r--drivers/power/regulator/rk8xx.c189
2 files changed, 266 insertions, 7 deletions
diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c
index 00c8a2e091..df0bf83a05 100644
--- a/drivers/power/pmic/rk8xx.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -10,6 +10,13 @@
#include <power/rk8xx_pmic.h>
#include <power/pmic.h>
+static struct reg_data rk817_init_reg[] = {
+/* enable the under-voltage protection,
+ * the under-voltage protection will shutdown the LDO3 and reset the PMIC
+ */
+ { RK817_BUCK4_CMIN, 0x60, 0x60},
+};
+
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
{ .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
@@ -76,13 +83,83 @@ static int rk8xx_bind(struct udevice *dev)
static int rk8xx_probe(struct udevice *dev)
{
struct rk8xx_priv *priv = dev_get_priv(dev);
- uint8_t msb, lsb;
+ struct reg_data *init_data = NULL;
+ int init_data_num = 0;
+ int ret = 0, i, show_variant;
+ u8 msb, lsb, id_msb, id_lsb;
+ u8 on_source = 0, off_source = 0;
+ u8 power_en0, power_en1, power_en2, power_en3;
+ u8 value;
/* read Chip variant */
- rk8xx_read(dev, ID_MSB, &msb, 1);
- rk8xx_read(dev, ID_LSB, &lsb, 1);
+ if (device_is_compatible(dev, "rockchip,rk817")) {
+ id_msb = RK817_ID_MSB;
+ id_lsb = RK817_ID_LSB;
+ } else {
+ id_msb = ID_MSB;
+ id_lsb = ID_LSB;
+ }
+
+ ret = rk8xx_read(dev, id_msb, &msb, 1);
+ if (ret)
+ return ret;
+ ret = rk8xx_read(dev, id_lsb, &lsb, 1);
+ if (ret)
+ return ret;
priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+ show_variant = priv->variant;
+ switch (priv->variant) {
+ case RK808_ID:
+ show_variant = 0x808; /* RK808 hardware ID is 0 */
+ break;
+ case RK805_ID:
+ case RK816_ID:
+ case RK818_ID:
+ on_source = RK8XX_ON_SOURCE;
+ off_source = RK8XX_OFF_SOURCE;
+ break;
+ case RK817_ID:
+ on_source = RK817_ON_SOURCE;
+ off_source = RK817_OFF_SOURCE;
+ init_data = rk817_init_reg;
+ init_data_num = ARRAY_SIZE(rk817_init_reg);
+ power_en0 = pmic_reg_read(dev, RK817_POWER_EN0);
+ power_en1 = pmic_reg_read(dev, RK817_POWER_EN1);
+ power_en2 = pmic_reg_read(dev, RK817_POWER_EN2);
+ power_en3 = pmic_reg_read(dev, RK817_POWER_EN3);
+
+ value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4);
+ pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value);
+ value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
+ pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
+ break;
+ default:
+ printf("Unknown PMIC: RK%x!!\n", priv->variant);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < init_data_num; i++) {
+ ret = pmic_clrsetbits(dev,
+ init_data[i].reg,
+ init_data[i].mask,
+ init_data[i].val);
+ if (ret < 0) {
+ printf("%s: i2c set reg 0x%x failed, ret=%d\n",
+ __func__, init_data[i].reg, ret);
+ }
+
+ debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg,
+ pmic_reg_read(dev, init_data[i].reg));
+ }
+
+ printf("PMIC: RK%x ", show_variant);
+
+ if (on_source && off_source)
+ printf("(on=0x%02x, off=0x%02x)",
+ pmic_reg_read(dev, on_source),
+ pmic_reg_read(dev, off_source));
+ printf("\n");
return 0;
}
@@ -97,6 +174,7 @@ static const struct udevice_id rk8xx_ids[] = {
{ .compatible = "rockchip,rk805" },
{ .compatible = "rockchip,rk808" },
{ .compatible = "rockchip,rk816" },
+ { .compatible = "rockchip,rk817" },
{ .compatible = "rockchip,rk818" },
{ }
};
diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c
index 466a871b7e..a5692edd00 100644
--- a/drivers/power/regulator/rk8xx.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -27,6 +27,21 @@
#define RK808_BUCK4_VSEL_MASK 0xf
#define RK808_LDO_VSEL_MASK 0x1f
+/* RK817 BUCK */
+#define RK817_BUCK_ON_VSEL(n) (0xbb + 3 * ((n) - 1))
+#define RK817_BUCK_SLP_VSEL(n) (0xbc + 3 * ((n) - 1))
+#define RK817_BUCK_VSEL_MASK 0x7f
+#define RK817_BUCK_CONFIG(i) (0xba + (i) * 3)
+
+/* RK817 LDO */
+#define RK817_LDO_ON_VSEL(n) (0xcc + 2 * ((n) - 1))
+#define RK817_LDO_SLP_VSEL(n) (0xcd + 2 * ((n) - 1))
+#define RK817_LDO_VSEL_MASK 0x7f
+
+/* RK817 ENABLE */
+#define RK817_POWER_EN(n) (0xb1 + (n))
+#define RK817_POWER_SLP_EN(n) (0xb5 + (n))
+
#define RK818_BUCK_VSEL_MASK 0x3f
#define RK818_BUCK4_VSEL_MASK 0x1f
#define RK818_LDO_VSEL_MASK 0x1f
@@ -45,13 +60,19 @@
#define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET)
#define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_OFFSET 3
-
#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_OFFSET 6
+#define RK817_RAMP_RATE_MASK (0x3 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_3MV_PER_US (0x0 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_6_3MV_PER_US (0x1 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_12_5MV_PER_US (0x2 << RK817_RAMP_RATE_OFFSET)
+#define RK817_RAMP_RATE_25MV_PER_US (0x3 << RK817_RAMP_RATE_OFFSET)
+
struct rk8xx_reg_info {
uint min_uv;
uint step_uv;
@@ -84,6 +105,25 @@ static const struct rk8xx_reg_info rk816_buck[] = {
{ 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
};
+static const struct rk8xx_reg_info rk817_buck[] = {
+ /* buck 1 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 2 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 3 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, },
+ /* buck 4 */
+ { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, },
+ { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, },
+ { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, },
+};
+
static const struct rk8xx_reg_info rk818_buck[] = {
{ 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
{ 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
@@ -112,6 +152,36 @@ static const struct rk8xx_reg_info rk816_ldo[] = {
{ 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
};
+static const struct rk8xx_reg_info rk817_ldo[] = {
+ /* ldo1 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo2 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo3 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo4 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo5 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo6 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo7 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo8 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, },
+ /* ldo9 */
+ { 600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, },
+ { 3400000, 0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, },
+};
+
static const struct rk8xx_reg_info rk818_ldo[] = {
{ 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
{ 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
@@ -152,6 +222,24 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
default:
return &rk816_buck[num + 4];
}
+
+ case RK817_ID:
+ switch (num) {
+ case 0 ... 2:
+ if (uvolt < 1500000)
+ return &rk817_buck[num * 3 + 0];
+ else if (uvolt < 2400000)
+ return &rk817_buck[num * 3 + 1];
+ else
+ return &rk817_buck[num * 3 + 2];
+ case 3:
+ if (uvolt < 1500000)
+ return &rk817_buck[num * 3 + 0];
+ else if (uvolt < 3400000)
+ return &rk817_buck[num * 3 + 1];
+ else
+ return &rk817_buck[num * 3 + 2];
+ }
case RK818_ID:
return &rk818_buck[num];
default:
@@ -189,7 +277,7 @@ static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
{
uint mask, value, en_reg;
- int ret;
+ int ret = 0;
struct rk8xx_priv *priv = dev_get_priv(pmic);
switch (priv->variant) {
@@ -220,6 +308,15 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
enable ? mask : 0);
break;
+ case RK817_ID:
+ if (buck < 4) {
+ if (enable)
+ value = ((1 << buck) | (1 << (buck + 4)));
+ else
+ value = ((0 << buck) | (1 << (buck + 4)));
+ ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
+ }
+ break;
default:
ret = -EINVAL;
}
@@ -272,6 +369,12 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
if (ret < 0)
return ret;
break;
+ case RK817_ID:
+ if (buck < 4) {
+ mask = 1 << buck;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
+ }
+ break;
}
if (ret < 0)
@@ -282,7 +385,7 @@ static int _buck_get_enable(struct udevice *pmic, int buck)
static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
{
- uint mask;
+ uint mask = 0;
int ret;
struct rk8xx_priv *priv = dev_get_priv(pmic);
@@ -299,6 +402,12 @@ static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
enable ? 0 : mask);
break;
+ case RK817_ID:
+ if (buck < 4)
+ mask = 1 << buck;
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+ enable ? mask : 0);
+ break;
default:
ret = -EINVAL;
}
@@ -310,7 +419,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
{
struct rk8xx_priv *priv = dev_get_priv(pmic);
int ret, val;
- uint mask;
+ uint mask = 0;
switch (priv->variant) {
case RK805_ID:
@@ -329,6 +438,15 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
return val;
ret = val & mask ? 0 : 1;
break;
+ case RK817_ID:
+ if (buck < 4)
+ mask = 1 << buck;
+
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ break;
default:
ret = -EINVAL;
}
@@ -345,6 +463,11 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
case RK805_ID:
case RK816_ID:
return &rk816_ldo[num];
+ case RK817_ID:
+ if (uvolt < 3400000)
+ return &rk817_ldo[num * 2 + 0];
+ else
+ return &rk817_ldo[num * 2 + 1];
case RK818_ID:
return &rk818_ldo[num];
default:
@@ -376,6 +499,20 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo)
if (ret < 0)
return ret;
break;
+ case RK817_ID:
+ if (ldo < 4) {
+ mask = 1 << ldo;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(1));
+ } else if (ldo < 8) {
+ mask = 1 << (ldo - 4);
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(2));
+ } else if (ldo == 8) {
+ mask = 1 << 0;
+ ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
+ } else {
+ return false;
+ }
+ break;
}
if (ret < 0)
@@ -412,6 +549,24 @@ static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
enable ? mask : 0);
break;
+ case RK817_ID:
+ if (ldo < 4) {
+ en_reg = RK817_POWER_EN(1);
+ } else if (ldo < 8) {
+ ldo -= 4;
+ en_reg = RK817_POWER_EN(2);
+ } else if (ldo == 8) {
+ ldo = 0; /* BIT 0 */
+ en_reg = RK817_POWER_EN(3);
+ } else {
+ return -EINVAL;
+ }
+ if (enable)
+ value = ((1 << ldo) | (1 << (ldo + 4)));
+ else
+ value = ((0 << ldo) | (1 << (ldo + 4)));
+ ret = pmic_reg_write(pmic, en_reg, value);
+ break;
}
return ret;
@@ -436,6 +591,17 @@ static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
enable ? 0 : mask);
break;
+ case RK817_ID:
+ if (ldo == 8) {
+ mask = 1 << 4; /* LDO9 */
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
+ enable ? mask : 0);
+ } else {
+ mask = 1 << ldo;
+ ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask,
+ enable ? mask : 0);
+ }
+ break;
}
return ret;
@@ -464,6 +630,21 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
return val;
ret = val & mask ? 0 : 1;
break;
+ case RK817_ID:
+ if (ldo == 8) {
+ mask = 1 << 4; /* LDO9 */
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ } else {
+ mask = 1 << ldo;
+ val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1));
+ if (val < 0)
+ return val;
+ ret = val & mask ? 1 : 0;
+ }
+ break;
}
return ret;