diff options
author | Tom Rini <trini@konsulko.com> | 2019-11-11 14:19:32 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-11-11 14:19:32 -0500 |
commit | 086e391bc46d3dda5c44053532bb51dc3827ee94 (patch) | |
tree | 0b550df896976ad003864a028417b16a66b58702 /drivers/power/regulator | |
parent | 0b73ef0c02313e651af4b0a8e206c7c4a198e7f8 (diff) | |
parent | f74a089e47e0b485fb70dcadfbf093daf64a740a (diff) |
Merge tag 'u-boot-rockchip-20191110' of https://gitlab.denx.de/u-boot/custodians/u-boot-rockchip
- Add support for rockchip pmic rk805,rk809, rk816, rk817
- Add rk3399 board Leez support
- Fix bug in rk3328 ram driver
- Adapt SPL to support ATF bl31 with entry at 0x40000
- Fix the u8 type comparision with '-1'.
- Fix checkpatch warning for multi blank line and review signature.
Diffstat (limited to 'drivers/power/regulator')
-rw-r--r-- | drivers/power/regulator/regulator-uclass.c | 70 | ||||
-rw-r--r-- | drivers/power/regulator/rk8xx.c | 939 |
2 files changed, 924 insertions, 85 deletions
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 76be95bcd1..90961de95c 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -77,6 +77,33 @@ int regulator_set_value(struct udevice *dev, int uV) return ret; } +int regulator_set_suspend_value(struct udevice *dev, int uV) +{ + const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV) + return -EINVAL; + if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV) + return -EINVAL; + + if (!ops->set_suspend_value) + return -ENOSYS; + + return ops->set_suspend_value(dev, uV); +} + +int regulator_get_suspend_value(struct udevice *dev) +{ + const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + + if (!ops->get_suspend_value) + return -ENOSYS; + + return ops->get_suspend_value(dev); +} + /* * To be called with at most caution as there is no check * before setting the actual voltage value. @@ -170,6 +197,26 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable) return ret; } +int regulator_set_suspend_enable(struct udevice *dev, bool enable) +{ + const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + + if (!ops->set_suspend_enable) + return -ENOSYS; + + return ops->set_suspend_enable(dev, enable); +} + +int regulator_get_suspend_enable(struct udevice *dev) +{ + const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + + if (!ops->get_suspend_enable) + return -ENOSYS; + + return ops->get_suspend_enable(dev); +} + int regulator_get_mode(struct udevice *dev) { const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); @@ -235,6 +282,14 @@ int regulator_autoset(struct udevice *dev) int ret = 0; uc_pdata = dev_get_uclass_platdata(dev); + + ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on); + if (!ret && uc_pdata->suspend_on) { + ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV); + if (!ret) + return ret; + } + if (!uc_pdata->always_on && !uc_pdata->boot_on) return -EMEDIUMTYPE; @@ -243,6 +298,8 @@ int regulator_autoset(struct udevice *dev) if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV) ret = regulator_set_value(dev, uc_pdata->min_uV); + if (uc_pdata->init_uV > 0) + ret = regulator_set_value(dev, uc_pdata->init_uV); if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)) ret = regulator_set_current(dev, uc_pdata->min_uA); @@ -363,6 +420,7 @@ static int regulator_post_bind(struct udevice *dev) static int regulator_pre_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; + ofnode node; uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) @@ -373,6 +431,8 @@ static int regulator_pre_probe(struct udevice *dev) -ENODATA); uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt", -ENODATA); + uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt", + -ENODATA); uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp", -ENODATA); uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp", @@ -382,6 +442,16 @@ static int regulator_pre_probe(struct udevice *dev) uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay", 0); + node = dev_read_subnode(dev, "regulator-state-mem"); + if (ofnode_valid(node)) { + uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend"); + if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV)) + uc_pdata->suspend_uV = uc_pdata->max_uV; + } else { + uc_pdata->suspend_on = true; + uc_pdata->suspend_uV = uc_pdata->max_uV; + } + /* Those values are optional (-ENODATA if unset) */ if ((uc_pdata->min_uV != -ENODATA) && (uc_pdata->max_uV != -ENODATA) && diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index aa4f3a161c..e99331f6c9 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -19,11 +19,33 @@ #define ENABLE_DRIVER #endif +/* Not used or exisit register and configure */ +#define NA 0xff + /* Field Definitions */ #define RK808_BUCK_VSEL_MASK 0x3f #define RK808_BUCK4_VSEL_MASK 0xf #define RK808_LDO_VSEL_MASK 0x1f +/* RK809 BUCK5 */ +#define RK809_BUCK5_CONFIG(n) (0xde + (n) * 1) +#define RK809_BUCK5_VSEL_MASK 0x07 + +/* 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 @@ -32,49 +54,156 @@ #define RK818_USB_ILIM_SEL_MASK 0x0f #define RK818_USB_CHG_SD_VSEL_MASK 0x70 +/* + * Ramp delay + */ +#define RK805_RAMP_RATE_OFFSET 3 +#define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET) +#define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET) +#define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET) +#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; - s8 vsel_reg; + u8 vsel_reg; + u8 vsel_sleep_reg; + u8 config_reg; u8 vsel_mask; + u8 min_sel; }; static const struct rk8xx_reg_info rk808_buck[] = { - { 712500, 12500, REG_BUCK1_ON_VSEL, RK808_BUCK_VSEL_MASK, }, - { 712500, 12500, REG_BUCK2_ON_VSEL, RK808_BUCK_VSEL_MASK, }, - { 712500, 12500, -1, RK808_BUCK_VSEL_MASK, }, - { 1800000, 100000, REG_BUCK4_ON_VSEL, RK808_BUCK4_VSEL_MASK, }, + { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, }, + { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, }, + { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, }, + { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, }, +}; + +static const struct rk8xx_reg_info rk816_buck[] = { + /* buck 1 */ + { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, }, + { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, }, + { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, }, + /* buck 2 */ + { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, }, + { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, }, + { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, }, + /* buck 3 */ + { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, }, + /* buck 4 */ + { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, }, +}; + +static const struct rk8xx_reg_info rk809_buck5[] = { + /* buck 5 */ + { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, }, + { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, }, + { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, }, + { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, }, +}; + +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, RK818_BUCK_VSEL_MASK, }, - { 712500, 12500, REG_BUCK2_ON_VSEL, RK818_BUCK_VSEL_MASK, }, - { 712500, 12500, -1, RK818_BUCK_VSEL_MASK, }, - { 1800000, 100000, REG_BUCK4_ON_VSEL, RK818_BUCK4_VSEL_MASK, }, + { 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, }, + { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, }, + { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, }, }; #ifdef ENABLE_DRIVER static const struct rk8xx_reg_info rk808_ldo[] = { - { 1800000, 100000, REG_LDO1_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO2_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO3_ON_VSEL, RK808_BUCK4_VSEL_MASK, }, - { 1800000, 100000, REG_LDO4_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO5_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO6_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO7_ON_VSEL, RK808_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO8_ON_VSEL, RK808_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, }, + { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, +}; + +static const struct rk8xx_reg_info rk816_ldo[] = { + { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 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, RK818_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO2_ON_VSEL, RK818_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO3_ON_VSEL, RK818_LDO3_ON_VSEL_MASK, }, - { 1800000, 100000, REG_LDO4_ON_VSEL, RK818_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO5_ON_VSEL, RK818_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO6_ON_VSEL, RK818_LDO_VSEL_MASK, }, - { 800000, 100000, REG_LDO7_ON_VSEL, RK818_LDO_VSEL_MASK, }, - { 1800000, 100000, REG_LDO8_ON_VSEL, RK818_LDO_VSEL_MASK, }, + { 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, }, + { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, }, + { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, + { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, }; #endif @@ -87,10 +216,54 @@ static const uint rk818_chrg_shutdown_vsel_array[] = { }; static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic, - int num) + int num, int uvolt) { struct rk8xx_priv *priv = dev_get_priv(pmic); + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + switch (num) { + case 0: + case 1: + if (uvolt <= 1450000) + return &rk816_buck[num * 3 + 0]; + else if (uvolt <= 2200000) + return &rk816_buck[num * 3 + 1]; + else + return &rk816_buck[num * 3 + 2]; + default: + return &rk816_buck[num + 4]; + } + + case RK809_ID: + 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]; + /* BUCK5 for RK809 */ + default: + if (uvolt < 1800000) + return &rk809_buck5[0]; + else if (uvolt < 2800000) + return &rk809_buck5[1]; + else if (uvolt < 3300000) + return &rk809_buck5[2]; + else + return &rk809_buck5[3]; + } case RK818_ID: return &rk818_buck[num]; default: @@ -100,44 +273,245 @@ static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic, static int _buck_set_value(struct udevice *pmic, int buck, int uvolt) { - const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck - 1); + const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt); + struct rk8xx_priv *priv = dev_get_priv(pmic); int mask = info->vsel_mask; int val; - if (info->vsel_reg == -1) + if (info->vsel_reg == NA) return -ENOSYS; - val = (uvolt - info->min_uv) / info->step_uv; - debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, - val); - return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); + if (info->step_uv == 0) /* Fixed voltage */ + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, buck + 1, info->vsel_reg, mask, val); + + if (priv->variant == RK816_ID) { + pmic_clrsetbits(pmic, info->vsel_reg, mask, val); + return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2, + 1 << 7, 1 << 7); + } else { + return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); + } } static int _buck_set_enable(struct udevice *pmic, int buck, bool enable) { - uint mask; - int ret; + uint mask, value, en_reg; + int ret = 0; + struct rk8xx_priv *priv = dev_get_priv(pmic); - buck--; - mask = 1 << buck; - if (enable) { - ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, 0, 3 << (buck * 2)); - if (ret) - return ret; - ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0); - if (ret) - return ret; + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + if (buck >= 4) { + buck -= 4; + en_reg = RK816_REG_DCDC_EN2; + } else { + en_reg = RK816_REG_DCDC_EN1; + } + if (enable) + value = ((1 << buck) | (1 << (buck + 4))); + else + value = ((0 << buck) | (1 << (buck + 4))); + ret = pmic_reg_write(pmic, en_reg, value); + break; + + case RK808_ID: + case RK818_ID: + mask = 1 << buck; + if (enable) { + ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, + 0, 3 << (buck * 2)); + if (ret) + return ret; + } + ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask, + enable ? mask : 0); + break; + case RK809_ID: + 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); + /* BUCK5 for RK809 */ + } else { + if (enable) + value = ((1 << 1) | (1 << 5)); + else + value = ((0 << 1) | (1 << 5)); + ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value); + } + break; + default: + ret = -EINVAL; } - return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0); + return ret; } #ifdef ENABLE_DRIVER +static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt) +{ + const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt); + int mask = info->vsel_mask; + int val; + + if (info->vsel_sleep_reg == NA) + return -ENOSYS; + + if (info->step_uv == 0) + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val); + + return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val); +} + +static int _buck_get_enable(struct udevice *pmic, int buck) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + uint mask = 0; + int ret = 0; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + if (buck >= 4) { + mask = 1 << (buck - 4); + ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2); + } else { + mask = 1 << buck; + ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1); + } + break; + case RK808_ID: + case RK818_ID: + mask = 1 << buck; + ret = pmic_reg_read(pmic, REG_DCDC_EN); + if (ret < 0) + return ret; + break; + case RK809_ID: + case RK817_ID: + if (buck < 4) { + mask = 1 << buck; + ret = pmic_reg_read(pmic, RK817_POWER_EN(0)); + /* BUCK5 for RK809 */ + } else { + mask = 1 << 1; + ret = pmic_reg_read(pmic, RK817_POWER_EN(3)); + } + break; + } + + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable) +{ + uint mask = 0; + int ret; + struct rk8xx_priv *priv = dev_get_priv(pmic); + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + mask = 1 << buck; + ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask, + enable ? mask : 0); + break; + case RK808_ID: + case RK818_ID: + mask = 1 << buck; + ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask, + enable ? 0 : mask); + break; + case RK809_ID: + case RK817_ID: + if (buck < 4) + mask = 1 << buck; + else + mask = 1 << 5; /* BUCK5 for RK809 */ + ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask, + enable ? mask : 0); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int _buck_get_suspend_enable(struct udevice *pmic, int buck) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + int ret, val; + uint mask = 0; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + mask = 1 << buck; + val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN); + if (val < 0) + return val; + ret = val & mask ? 1 : 0; + break; + case RK808_ID: + case RK818_ID: + mask = 1 << buck; + val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1); + if (val < 0) + return val; + ret = val & mask ? 0 : 1; + break; + case RK809_ID: + case RK817_ID: + if (buck < 4) + mask = 1 << buck; + else + mask = 1 << 5; /* BUCK5 for RK809 */ + + val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0)); + if (val < 0) + return val; + ret = val & mask ? 1 : 0; + break; + default: + ret = -EINVAL; + } + + return ret; +} + static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic, - int num) + int num, int uvolt) { struct rk8xx_priv *priv = dev_get_priv(pmic); + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + return &rk816_ldo[num]; + case RK809_ID: + 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: @@ -145,15 +519,196 @@ static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic, } } +static int _ldo_get_enable(struct udevice *pmic, int ldo) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + uint mask = 0; + int ret = 0; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + if (ldo >= 4) { + mask = 1 << (ldo - 4); + ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2); + } else { + mask = 1 << ldo; + ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1); + } + break; + case RK808_ID: + case RK818_ID: + mask = 1 << ldo; + ret = pmic_reg_read(pmic, REG_LDO_EN); + if (ret < 0) + return ret; + break; + case RK809_ID: + 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) + return ret; + + return ret & mask ? true : false; +} + +static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + uint mask, value, en_reg; + int ret = 0; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + if (ldo >= 4) { + ldo -= 4; + en_reg = RK816_REG_LDO_EN2; + } else { + en_reg = RK816_REG_LDO_EN1; + } + if (enable) + value = ((1 << ldo) | (1 << (ldo + 4))); + else + value = ((0 << ldo) | (1 << (ldo + 4))); + + ret = pmic_reg_write(pmic, en_reg, value); + break; + case RK808_ID: + case RK818_ID: + mask = 1 << ldo; + ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask, + enable ? mask : 0); + break; + case RK809_ID: + 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; +} + +static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + uint mask; + int ret = 0; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + mask = 1 << ldo; + ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask, + enable ? mask : 0); + break; + case RK808_ID: + case RK818_ID: + mask = 1 << ldo; + ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask, + enable ? 0 : mask); + break; + case RK809_ID: + 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; +} + +static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo) +{ + struct rk8xx_priv *priv = dev_get_priv(pmic); + int val, ret = 0; + uint mask; + + switch (priv->variant) { + case RK805_ID: + case RK816_ID: + mask = 1 << ldo; + val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN); + if (val < 0) + return val; + ret = val & mask ? 1 : 0; + break; + case RK808_ID: + case RK818_ID: + mask = 1 << ldo; + val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2); + if (val < 0) + return val; + ret = val & mask ? 0 : 1; + break; + case RK809_ID: + 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; +} + static int buck_get_value(struct udevice *dev) { int buck = dev->driver_data - 1; - const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck); + /* We assume level-1 voltage is enough for usage in U-Boot */ + const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0); int mask = info->vsel_mask; int ret, val; - if (info->vsel_reg == -1) + if (info->vsel_reg == NA) return -ENOSYS; + ret = pmic_reg_read(dev->parent, info->vsel_reg); if (ret < 0) return ret; @@ -164,41 +719,74 @@ static int buck_get_value(struct udevice *dev) static int buck_set_value(struct udevice *dev, int uvolt) { - int buck = dev->driver_data; + int buck = dev->driver_data - 1; return _buck_set_value(dev->parent, buck, uvolt); } +static int buck_get_suspend_value(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + /* We assume level-1 voltage is enough for usage in U-Boot */ + const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0); + int mask = info->vsel_mask; + int ret, val; + + if (info->vsel_sleep_reg == NA) + return -ENOSYS; + + ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg); + if (ret < 0) + return ret; + + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int buck_set_suspend_value(struct udevice *dev, int uvolt) +{ + int buck = dev->driver_data - 1; + + return _buck_set_suspend_value(dev->parent, buck, uvolt); +} + static int buck_set_enable(struct udevice *dev, bool enable) { - int buck = dev->driver_data; + int buck = dev->driver_data - 1; return _buck_set_enable(dev->parent, buck, enable); } -static int buck_get_enable(struct udevice *dev) +static int buck_set_suspend_enable(struct udevice *dev, bool enable) { int buck = dev->driver_data - 1; - int ret; - uint mask; - mask = 1 << buck; + return _buck_set_suspend_enable(dev->parent, buck, enable); +} - ret = pmic_reg_read(dev->parent, REG_DCDC_EN); - if (ret < 0) - return ret; +static int buck_get_suspend_enable(struct udevice *dev) +{ + int buck = dev->driver_data - 1; - return ret & mask ? true : false; + return _buck_get_suspend_enable(dev->parent, buck); +} + +static int buck_get_enable(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + + return _buck_get_enable(dev->parent, buck); } static int ldo_get_value(struct udevice *dev) { int ldo = dev->driver_data - 1; - const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo); + const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0); int mask = info->vsel_mask; int ret, val; - if (info->vsel_reg == -1) + if (info->vsel_reg == NA) return -ENOSYS; ret = pmic_reg_read(dev->parent, info->vsel_reg); if (ret < 0) @@ -211,71 +799,238 @@ static int ldo_get_value(struct udevice *dev) static int ldo_set_value(struct udevice *dev, int uvolt) { int ldo = dev->driver_data - 1; - const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo); + const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt); int mask = info->vsel_mask; int val; - if (info->vsel_reg == -1) + if (info->vsel_reg == NA) return -ENOSYS; - val = (uvolt - info->min_uv) / info->step_uv; - debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, - val); + + if (info->step_uv == 0) + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, ldo + 1, info->vsel_reg, mask, val); return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val); } -static int ldo_set_enable(struct udevice *dev, bool enable) +static int ldo_set_suspend_value(struct udevice *dev, int uvolt) { int ldo = dev->driver_data - 1; - uint mask; + const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt); + int mask = info->vsel_mask; + int val; - mask = 1 << ldo; + if (info->vsel_sleep_reg == NA) + return -ENOSYS; - return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask, - enable ? mask : 0); + if (info->step_uv == 0) + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val); + + return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val); } -static int ldo_get_enable(struct udevice *dev) +static int ldo_get_suspend_value(struct udevice *dev) { int ldo = dev->driver_data - 1; - int ret; - uint mask; + const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0); + int mask = info->vsel_mask; + int val, ret; - mask = 1 << ldo; + if (info->vsel_sleep_reg == NA) + return -ENOSYS; - ret = pmic_reg_read(dev->parent, REG_LDO_EN); + ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg); if (ret < 0) return ret; - return ret & mask ? true : false; + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + int ldo = dev->driver_data - 1; + + return _ldo_set_enable(dev->parent, ldo, enable); +} + +static int ldo_set_suspend_enable(struct udevice *dev, bool enable) +{ + int ldo = dev->driver_data - 1; + + return _ldo_set_suspend_enable(dev->parent, ldo, enable); +} + +static int ldo_get_suspend_enable(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + + return _ldo_get_suspend_enable(dev->parent, ldo); +} + +static int ldo_get_enable(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + + return _ldo_get_enable(dev->parent, ldo); } static int switch_set_enable(struct udevice *dev, bool enable) { - int sw = dev->driver_data - 1; - uint mask; + struct rk8xx_priv *priv = dev_get_priv(dev->parent); + int ret = 0, sw = dev->driver_data - 1; + uint mask = 0; + + switch (priv->variant) { + case RK808_ID: + mask = 1 << (sw + 5); + ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, + enable ? mask : 0); + break; + case RK809_ID: + mask = (1 << (sw + 2)) | (1 << (sw + 6)); + ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask, + enable ? mask : 0); + break; + case RK818_ID: + mask = 1 << 6; + ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, + enable ? mask : 0); + break; + } - mask = 1 << (sw + 5); + debug("%s: switch%d, enable=%d, mask=0x%x\n", + __func__, sw + 1, enable, mask); - return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, - enable ? mask : 0); + return ret; } static int switch_get_enable(struct udevice *dev) { - int sw = dev->driver_data - 1; - int ret; - uint mask; + struct rk8xx_priv *priv = dev_get_priv(dev->parent); + int ret = 0, sw = dev->driver_data - 1; + uint mask = 0; - mask = 1 << (sw + 5); + switch (priv->variant) { + case RK808_ID: + mask = 1 << (sw + 5); + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + break; + case RK809_ID: + mask = 1 << (sw + 2); + ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3)); + break; + case RK818_ID: + mask = 1 << 6; + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + break; + } - ret = pmic_reg_read(dev->parent, REG_DCDC_EN); if (ret < 0) return ret; return ret & mask ? true : false; } +static int switch_set_suspend_value(struct udevice *dev, int uvolt) +{ + return 0; +} + +static int switch_get_suspend_value(struct udevice *dev) +{ + return 0; +} + +static int switch_set_suspend_enable(struct udevice *dev, bool enable) +{ + struct rk8xx_priv *priv = dev_get_priv(dev->parent); + int ret = 0, sw = dev->driver_data - 1; + uint mask = 0; + + switch (priv->variant) { + case RK808_ID: + mask = 1 << (sw + 5); + ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask, + enable ? 0 : mask); + break; + case RK809_ID: + mask = 1 << (sw + 6); + ret = pmic_clrsetbits(dev->parent, RK817_POWER_SLP_EN(0), mask, + enable ? mask : 0); + break; + case RK818_ID: + mask = 1 << 6; + ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask, + enable ? 0 : mask); + break; + } + + debug("%s: switch%d, enable=%d, mask=0x%x\n", + __func__, sw + 1, enable, mask); + + return ret; +} + +static int switch_get_suspend_enable(struct udevice *dev) +{ + struct rk8xx_priv *priv = dev_get_priv(dev->parent); + int val, ret = 0, sw = dev->driver_data - 1; + uint mask = 0; + + switch (priv->variant) { + case RK808_ID: + mask = 1 << (sw + 5); + val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); + if (val < 0) + return val; + ret = val & mask ? 0 : 1; + break; + case RK809_ID: + mask = 1 << (sw + 6); + val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0)); + if (val < 0) + return val; + ret = val & mask ? 1 : 0; + break; + case RK818_ID: + mask = 1 << 6; + val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); + if (val < 0) + return val; + ret = val & mask ? 0 : 1; + break; + } + + return ret; +} + +/* + * RK8xx switch does not need to set the voltage, + * but if dts set regulator-min-microvolt/regulator-max-microvolt, + * will cause regulator set value fail and not to enable this switch. + * So add an empty function to return success. + */ +static int switch_get_value(struct udevice *dev) +{ + return 0; +} + +static int switch_set_value(struct udevice *dev, int uvolt) +{ + return 0; +} + static int rk8xx_buck_probe(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; @@ -315,20 +1070,34 @@ static int rk8xx_switch_probe(struct udevice *dev) static const struct dm_regulator_ops rk8xx_buck_ops = { .get_value = buck_get_value, .set_value = buck_set_value, + .set_suspend_value = buck_set_suspend_value, + .get_suspend_value = buck_get_suspend_value, .get_enable = buck_get_enable, .set_enable = buck_set_enable, + .set_suspend_enable = buck_set_suspend_enable, + .get_suspend_enable = buck_get_suspend_enable, }; static const struct dm_regulator_ops rk8xx_ldo_ops = { .get_value = ldo_get_value, .set_value = ldo_set_value, + .set_suspend_value = ldo_set_suspend_value, + .get_suspend_value = ldo_get_suspend_value, .get_enable = ldo_get_enable, .set_enable = ldo_set_enable, + .set_suspend_enable = ldo_set_suspend_enable, + .get_suspend_enable = ldo_get_suspend_enable, }; static const struct dm_regulator_ops rk8xx_switch_ops = { + .get_value = switch_get_value, + .set_value = switch_set_value, .get_enable = switch_get_enable, .set_enable = switch_set_enable, + .set_suspend_enable = switch_set_suspend_enable, + .get_suspend_enable = switch_get_suspend_enable, + .set_suspend_value = switch_set_suspend_value, + .get_suspend_value = switch_get_suspend_value, }; U_BOOT_DRIVER(rk8xx_buck) = { |