summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plat/sun50iw1p1/plat_pm.c4
-rw-r--r--plat/sun50iw1p1/sunxi_power.c518
-rw-r--r--plat/sun50iw1p1/sunxi_power.h83
-rw-r--r--plat/sun50iw1p1/sunxi_private.h6
4 files changed, 567 insertions, 44 deletions
diff --git a/plat/sun50iw1p1/plat_pm.c b/plat/sun50iw1p1/plat_pm.c
index ec26248..922e497 100644
--- a/plat/sun50iw1p1/plat_pm.c
+++ b/plat/sun50iw1p1/plat_pm.c
@@ -254,7 +254,9 @@ static int32_t sunxi_affinst_suspend_finish(uint64_t mpidr,
******************************************************************************/
static void __dead2 sunxi_system_off(void)
{
- sunxi_pmic_write(0x32, sunxi_pmic_read(0x32) | 0x80);
+ uint8_t val;
+ sunxi_pmic_read(0x32, &val);
+ sunxi_pmic_write(0x32, val | 0x80);
ERROR("PSCI system shutdown: still alive ...\n");
wfi();
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
index 827f0d5..5a7668d 100644
--- a/plat/sun50iw1p1/sunxi_power.c
+++ b/plat/sun50iw1p1/sunxi_power.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (C) 2017, Theobroma Systems.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -35,69 +36,509 @@
#include "sunxi_def.h"
#include "sunxi_private.h"
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define BIT(n) (1U << (n))
+
+/* RSB-RT address of the AXP803 */
#define PMIC_RSB_RT_ADDR 0x2d
-int sunxi_pmic_read(uint8_t reg)
+#define DVM_FINISHED_BIT BIT(7)
+
+struct regulator_details {
+ enum axp803_regulator regulator;
+
+ /*
+ * For two-step regulators:
+ * mvolt_low-mvolt_mid: mvolt_step1 / step
+ * mvolt_mid+mvolt_step2-mvolt_high: mvolt_step2 / step
+ *
+ * For one-step regulators (set mvolt_mid and mvolt_step2 to 0):
+ * mvolt_low-mvolt_high: mvolt_step1 / step
+ */
+ uint32_t mvolt_low;
+ uint32_t mvolt_mid;
+ uint32_t mvolt_high;
+ uint32_t mvolt_step1;
+ uint32_t mvolt_step2;
+ uint32_t voltage_control_reg;
+ int dvm; /* DVM used or not */
+ uint32_t onoff_control_reg;
+ uint8_t onoff_control_bit;
+};
+
+static struct regulator_details regulator_details[] = {
+ {
+ .regulator = AXP803_DLDO1,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x15,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 3,
+ }, {
+ .regulator = AXP803_DLDO2,
+ .mvolt_low = 700,
+ .mvolt_mid = 3400,
+ .mvolt_high = 4200,
+ .mvolt_step1 = 100,
+ .mvolt_step2 = 200,
+ .voltage_control_reg = 0x16,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 4,
+ }, {
+ .regulator = AXP803_DLDO3,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x15,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 5,
+ }, {
+ .regulator = AXP803_DLDO4,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x18,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 6,
+ }, {
+ .regulator = AXP803_ELDO1,
+ .mvolt_low = 700,
+ .mvolt_high = 1900,
+ .mvolt_step1 = 50,
+ .voltage_control_reg = 0x19,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 0,
+ }, {
+ .regulator = AXP803_ELDO2,
+ .mvolt_low = 700,
+ .mvolt_high = 1900,
+ .mvolt_step1 = 50,
+ .voltage_control_reg = 0x1a,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 1,
+ }, {
+ .regulator = AXP803_ELDO3,
+ .mvolt_low = 700,
+ .mvolt_high = 1900,
+ .mvolt_step1 = 50,
+ .voltage_control_reg = 0x1b,
+ .onoff_control_reg = 0x12,
+ .onoff_control_bit = 2,
+ }, {
+ .regulator = AXP803_FLDO1,
+ .mvolt_low = 700,
+ .mvolt_high = 1450,
+ .mvolt_step1 = 50,
+ .voltage_control_reg = 0x1c,
+ .onoff_control_reg = 0x13,
+ .onoff_control_bit = 2,
+ }, {
+ .regulator = AXP803_FLDO2,
+ .mvolt_low = 700,
+ .mvolt_high = 1450,
+ .mvolt_step1 = 50,
+ .voltage_control_reg = 0x1d,
+ .onoff_control_reg = 0x13,
+ .onoff_control_bit = 3,
+ }, {
+ .regulator = AXP803_DCDC1,
+ .mvolt_low = 1600,
+ .mvolt_high = 3400,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x20,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 0,
+ }, {
+ .regulator = AXP803_DCDC2,
+ .mvolt_low = 500,
+ .mvolt_mid = 1200,
+ .mvolt_high = 1300,
+ .mvolt_step1 = 10,
+ .mvolt_step2 = 20,
+ .voltage_control_reg = 0x21,
+ .dvm = 1,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 1,
+ }, {
+ .regulator = AXP803_DCDC3,
+ .mvolt_low = 500,
+ .mvolt_mid = 1200,
+ .mvolt_high = 1300,
+ .mvolt_step1 = 10,
+ .mvolt_step2 = 20,
+ .voltage_control_reg = 0x22,
+ .dvm = 1,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 2,
+ }, {
+ .regulator = AXP803_DCDC4,
+ .mvolt_low = 500,
+ .mvolt_mid = 1200,
+ .mvolt_high = 1300,
+ .mvolt_step1 = 10,
+ .mvolt_step2 = 20,
+ .voltage_control_reg = 0x23,
+ .dvm = 1,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 3,
+ }, {
+ .regulator = AXP803_DCDC5,
+ .mvolt_low = 800,
+ .mvolt_mid = 1120,
+ .mvolt_high = 1840,
+ .mvolt_step1 = 10,
+ .mvolt_step2 = 20,
+ .voltage_control_reg = 0x24,
+ .dvm = 1,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 4,
+ }, {
+ .regulator = AXP803_DCDC6,
+ .mvolt_low = 600,
+ .mvolt_mid = 1100,
+ .mvolt_high = 1520,
+ .mvolt_step1 = 10,
+ .mvolt_step2 = 20,
+ .voltage_control_reg = 0x25,
+ .dvm = 1,
+ .onoff_control_reg = 0x10,
+ .onoff_control_bit = 5,
+ }, {
+ .regulator = AXP803_ALDO1,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x28,
+ .onoff_control_reg = 0x13,
+ .onoff_control_bit = 5,
+ }, {
+ .regulator = AXP803_ALDO2,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x29,
+ .onoff_control_reg = 0x13,
+ .onoff_control_bit = 6,
+ }, {
+ .regulator = AXP803_ALDO3,
+ .mvolt_low = 700,
+ .mvolt_high = 3300,
+ .mvolt_step1 = 100,
+ .voltage_control_reg = 0x2a,
+ .onoff_control_reg = 0x13,
+ .onoff_control_bit = 7,
+ }
+};
+
+static struct regulator_details* get_regulator_details(enum axp803_regulator r)
{
- uint32_t val;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(regulator_details); i++) {
+ struct regulator_details *rd = &regulator_details[i];
+
+ if (rd->regulator == r)
+ return rd;
+ }
+ return NULL;
+}
+
+int sunxi_pmic_read(uint8_t reg, uint8_t *val)
+{
+ uint32_t v;
int ret;
- ret = rsb_read(PMIC_RSB_RT_ADDR, reg, &val, 1);
+ ret = rsb_read(PMIC_RSB_RT_ADDR, reg, &v, 1);
if (ret)
return ret;
+
+ *val = v;
+
+ VERBOSE("PMIC read @0x%x: 0x%x\n", reg, *val);
+
+ return 0;
+}
+
+int sunxi_pmic_write(uint8_t reg, uint8_t val)
+{
+ VERBOSE("PMIC write @0x%x: 0x%x\n", reg, val);
+ return rsb_write(PMIC_RSB_RT_ADDR, reg, val, 1);
+}
+
+static int sunxi_pmic_set_bit_val(uint8_t reg, uint8_t bit, uint32_t v)
+{
+ uint8_t old_val, new_val;
+ int ret;
+
+ ret = sunxi_pmic_read(reg, &old_val);
+ if (ret < 0)
+ return ret;
+
+ if (v)
+ new_val = old_val | BIT(bit);
+ else
+ new_val = old_val & (~BIT(bit));
+
+ if (old_val != new_val)
+ ret = sunxi_pmic_write(reg, new_val);
+ else
+ ret = 0;
+
+ return ret;
+}
+
+int sunxi_pmic_set_bit(uint8_t reg, uint8_t bit)
+{
+ return sunxi_pmic_set_bit_val(reg, bit, 1);
+}
+
+int sunxi_pmic_clear_bit(uint8_t reg, uint8_t bit)
+{
+ return sunxi_pmic_set_bit_val(reg, bit, 0);
+}
+
+static uint8_t mvolt_to_val(struct regulator_details *rd, uint32_t mvolt)
+{
+ uint8_t val;
+
+ if (mvolt < rd->mvolt_low)
+ mvolt = rd->mvolt_low;
+
+ if (mvolt > rd->mvolt_high)
+ mvolt = rd->mvolt_high;
+
+ if (rd->mvolt_mid != 0 && mvolt > rd->mvolt_mid) {
+ val = (rd->mvolt_mid - rd->mvolt_low) / rd->mvolt_step1;
+ val += (mvolt - rd->mvolt_mid) / rd->mvolt_step2;
+ } else
+ val = (mvolt - rd->mvolt_low) / rd->mvolt_step1;
+
return val;
}
-int sunxi_pmic_write(uint8_t reg, uint8_t value)
+static uint32_t val_to_mvolt(struct regulator_details *rd, uint8_t val)
{
- return rsb_write(PMIC_RSB_RT_ADDR, reg, value, 1);
+ uint32_t step1_max = rd->mvolt_mid / rd->mvolt_step1;
+ uint32_t mvolt;
+
+ if (rd->mvolt_mid != 0 && val > step1_max) {
+ mvolt = rd->mvolt_mid;
+ mvolt += (val - step1_max) * rd->mvolt_step2;
+ } else
+ mvolt = rd->mvolt_low + val * rd->mvolt_step1;
+
+ return mvolt;
}
-/* Setup the PMIC: DCDC1 to 3.3V, enable DC1SW and DLDO4 */
-static int pmic_setup(void)
+int sunxi_pmic_set_voltage(enum axp803_regulator r, uint32_t mvolt)
{
int ret;
+ struct regulator_details *rd;
+
+ rd = get_regulator_details(r);
+ if (!rd) {
+ ERROR("Unknown regulator!\n");
+ return -1;
+ }
+
+ /* Get the register value */
+ uint8_t val = mvolt_to_val(rd, mvolt);
+
+ /* Set voltage control to desired voltage */
+ ret = sunxi_pmic_write(rd->voltage_control_reg, val);
+ if (ret < 0) {
+ ERROR("Failed to set voltage of regulator %d to %u mV!\n",
+ r, mvolt);
+ return ret;
+ }
- ret = sunxi_pmic_read(0x20);
- if (ret != 0x0e && ret != 0x11) {
- int voltage = (ret & 0x1f) * 10 + 16;
+ if (rd->dvm) {
+ /* Wait until the finished flag is set */
+ do {
+ ret = sunxi_pmic_read(rd->voltage_control_reg, &val);
+ if (ret < 0) {
+ ERROR("Failed to read DVM finished flag (%d)!\n", ret);
+ return ret;
+ }
+ } while (!(val & DVM_FINISHED_BIT));
+ }
+
+ return 0;
+}
- NOTICE("PMIC: DCDC1 voltage is an unexpected %d.%dV\n",
- voltage / 10, voltage % 10);
+int sunxi_pmic_get_voltage(enum axp803_regulator r, uint32_t *mvolt)
+{
+ int ret;
+ uint8_t val;
+ struct regulator_details *rd;
+
+ rd = get_regulator_details(r);
+ if (!rd) {
+ ERROR("Unknown regulator!\n");
return -1;
}
- if (ret != 0x11) {
- /* Set DCDC1 voltage to 3.3 Volts */
- ret = sunxi_pmic_write(0x20, 0x11);
- if (ret < 0) {
- NOTICE("PMIC: error %d writing DCDC1 voltage\n", ret);
- return -2;
- }
+ /* Get the register value */
+ ret = sunxi_pmic_read(rd->voltage_control_reg, &val);
+ if (ret < 0) {
+ ERROR("Failed to read voltage control register (%d)!\n", ret);
+ return ret;
}
- ret = sunxi_pmic_read(0x12);
- if ((ret & 0x3f) != 0x01) {
- NOTICE("PMIC: Output power control 2 is an unexpected 0x%x\n",
- ret);
- return -3;
+ /* Remove DVM bit */
+ val &= ~DVM_FINISHED_BIT;
+
+ /* Get the mvolt value */
+ *mvolt = val_to_mvolt(rd, val);
+
+ return 0;
+}
+
+int sunxi_pmic_set_enable(enum axp803_regulator r, uint32_t enable)
+{
+ int ret;
+ struct regulator_details *rd;
+
+ rd = get_regulator_details(r);
+ if (!rd) {
+ ERROR("Unknown regulator!\n");
+ return -1;
+ }
+
+ ret = sunxi_pmic_set_bit_val(rd->onoff_control_reg,
+ rd->onoff_control_bit, enable);
+ if (ret < 0) {
+ ERROR("Failed to set enable bit of regulator (%d)!\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int sunxi_pmic_get_enable(enum axp803_regulator r, uint32_t *enable)
+{
+ int ret;
+ uint8_t val;
+ struct regulator_details *rd;
+
+ rd = get_regulator_details(r);
+ if (!rd) {
+ ERROR("Unknown regulator!\n");
+ return -1;
}
- if ((ret & 0xc1) != 0xc1) {
- /* Enable DC1SW to power PHY and DLDO4 for WiFi */
- ret = sunxi_pmic_write(0x12, ret | 0xc0);
- if (ret < 0) {
- NOTICE("PMIC: error %d enabling DC1SW/DLDO4\n", ret);
- return -4;
+ ret = sunxi_pmic_read(rd->onoff_control_reg, &val);
+ if (ret < 0) {
+ ERROR("Failed to read onoff control register (%d)!\n", ret);
+ return ret;
+ }
+
+ *enable = (val & BIT(rd->onoff_control_bit)) ? 1 : 0;
+
+ return 0;
+}
+
+int sunxi_pmic_run_tasks(struct pmic_task *tasks, size_t tasks_num)
+{
+ size_t i;
+
+ for (i = 0; i < tasks_num; i++) {
+ VERBOSE("Running PMIC task %zu\n", i);
+ struct pmic_task *t = &tasks[i];
+ if (t->t == PMIC_SET_VOLTAGE) {
+ int ret = sunxi_pmic_set_voltage(t->r, t->val);
+ if (ret) {
+ ERROR("Could run set-voltage task #%zu!", i);
+ return -1;
+ }
+ } else if (t->t == PMIC_SET_ENABLE) {
+ int ret = sunxi_pmic_set_enable(t->r, t->val);
+ if (ret) {
+ ERROR("Could run set-enable task #%zu!", i);
+ return -1;
+ }
+ } else {
+ ERROR("Could run unknown task #%zu!", i);
+ return -1;
}
}
- ret = sunxi_pmic_read(0x10);
- sunxi_pmic_write(0x10, ret | (1 << 3));
+ return 0;
+}
- sunxi_pmic_write(0x23, 0x46); /* DCDC4 = ETH PHY = 1.2V */
- sunxi_pmic_write(0x24, 0x2c); /* DCDC5 = DDR3L voltage = 1.36V */
- // sunxi_pmic_write(0x24, 0xb3); /* DCDC5 = DDR RAM voltage = 1.5V */
+static int pmic_setup(void)
+{
+ int ret;
+
+ /*
+ * (Verified) default values of AXP803 (see table 9-29):
+ * DCDC1: 3V0 on -> 3V3
+ * DCDC2: 1V1 on -> 1V04
+ * DCDC3: 1V1 on -> (dual-phase)
+ * DCDC4: 1V1 off -> 1V2 on
+ * DCDC5: 1V5 on -> 1V36
+ * DCDC6: 1V1 on
+ * ALDO1: 3V3 off -> on
+ * ALDO2: 1V8 on -> 3V3 on
+ * ALDO3: 3V0 on -> 3V3
+ * ELDO1: 1V8 on
+ * ELDO2: 0V7 off
+ * ELDO3: 0V7 off
+ * DLDO1: 3V3 off
+ * DLDO2: 2V9 off
+ * DLDO3: 2V9 off
+ * DLDO4: 3V3 off
+ * FLDO1: 1V2 off -> on
+ * FLDO2: 1V1 on
+ *
+ * DC1SW: off -> on
+ * DCDC2/3 dual-phase: off -> on
+ * DCDC5/6 dual-phase: off
+ */
+
+ /* Turn on DC1SW (part of DCDC1) */
+ ret = sunxi_pmic_set_bit(0x12, 7);
+ if (ret < 0) {
+ ERROR("Could not turn on DC1SW\n");
+ return -1;
+ }
+
+ /* Set DCDC2 and DCDC3 to dual-phase mode */
+ ret = sunxi_pmic_set_bit(0x14, 6);
+ if (ret < 0) {
+ ERROR("Could not enable dual-phase for DCDC2/3\n");
+ return -1;
+ }
+
+ struct pmic_task tasks[] = {
+ /* Set DCDC1 to 3V3 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_DCDC1, .val = 3300 },
+ /* Set DCDC2/3 to 1V04 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_DCDC2, .val = 1040 },
+ /* Set DCDC4 (ETH PHY) to 1V2 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_DCDC4, .val = 1200 },
+ /* Enable DCDC4 */
+ { .t = PMIC_SET_ENABLE, .r = AXP803_DCDC4, .val = 1 },
+ /* Set DCDC5 (DDR3L) to 1V36 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_DCDC5, .val = 1360 },
+ /* Enable ALDO1 */
+ { .t = PMIC_SET_ENABLE, .r = AXP803_ALDO1, .val = 1 },
+ /* Set ALDO2 to 3V3 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_ALDO2, .val = 3300 },
+ /* Enable ALDO2 */
+ { .t = PMIC_SET_ENABLE, .r = AXP803_ALDO2, .val = 1 },
+ /* Set ALDO3 to 3V3 */
+ { .t = PMIC_SET_VOLTAGE, .r = AXP803_ALDO3, .val = 3300 },
+ /* Enable FLDO1 */
+ { .t = PMIC_SET_ENABLE, .r = AXP803_FLDO1, .val = 1 },
+ };
+
+ ret = sunxi_pmic_run_tasks(tasks, ARRAY_SIZE(tasks));
+ if (ret < 0) {
+ ERROR("Could not run PMIC tasks\n");
+ return -1;
+ }
return 0;
}
@@ -108,19 +549,20 @@ static int pmic_setup(void)
int sunxi_pmic_setup(void)
{
int ret;
+ uint8_t val;
NOTICE("Configuring AXP PMIC\n");
/* Test PMIC communication */
- ret = sunxi_pmic_read(0x03);
+ ret = sunxi_pmic_read(0x03, &val);
if (ret < 0) {
ERROR("PMIC: error %d reading PMIC IC type register\n", ret);
return -2;
}
/* Check IC type number equals 0b01xx00001 */
- if ((ret & 0xcf) != 0x41) {
- ERROR("PMIC: unknown PMIC IC type 0x%x\n", ret);
+ if ((val & 0xcf) != 0x41) {
+ ERROR("PMIC: unknown PMIC IC type 0x%x\n", val);
return -3;
}
diff --git a/plat/sun50iw1p1/sunxi_power.h b/plat/sun50iw1p1/sunxi_power.h
new file mode 100644
index 0000000..566c59c
--- /dev/null
+++ b/plat/sun50iw1p1/sunxi_power.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017, Theobroma Systems.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SUNXI_POWER_H__
+#define __SUNXI_POWER_H__
+
+#include <bl_common.h>
+#include <platform_def.h>
+
+int sunxi_pmic_setup(void);
+
+/* Register-level access */
+int sunxi_pmic_read(uint8_t address, uint8_t *value);
+int sunxi_pmic_write(uint8_t address, uint8_t value);
+int sunxi_pmic_set_bit(uint8_t address, uint8_t bit);
+int sunxi_pmic_clear_bit(uint8_t address, uint8_t bit);
+
+/* Regulator-level access */
+enum axp803_regulator {
+ AXP803_DLDO1,
+ AXP803_DLDO2,
+ AXP803_DLDO3,
+ AXP803_DLDO4,
+ AXP803_ELDO1,
+ AXP803_ELDO2,
+ AXP803_ELDO3,
+ AXP803_FLDO1,
+ AXP803_FLDO2,
+ AXP803_DCDC1,
+ AXP803_DCDC2,
+ AXP803_DCDC3,
+ AXP803_DCDC4,
+ AXP803_DCDC5,
+ AXP803_DCDC6,
+ AXP803_ALDO1,
+ AXP803_ALDO2,
+ AXP803_ALDO3,
+};
+int sunxi_pmic_set_voltage(enum axp803_regulator r, uint32_t mvolt);
+int sunxi_pmic_get_voltage(enum axp803_regulator r, uint32_t *mvolt);
+int sunxi_pmic_set_enable(enum axp803_regulator r, uint32_t enable);
+int sunxi_pmic_get_enable(enum axp803_regulator r, uint32_t *enable);
+
+/* Task-level access */
+enum pmic_task_type {
+ PMIC_SET_VOLTAGE,
+ PMIC_SET_ENABLE,
+};
+struct pmic_task {
+ enum pmic_task_type t;
+ enum axp803_regulator r;
+ uint32_t val; /* mvolt or enable */
+};
+int sunxi_pmic_run_tasks(struct pmic_task *tasks, size_t tasks_num);
+
+#endif /* __SUNXI_POWER_H__ */
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
index 34e36d8..4093f55 100644
--- a/plat/sun50iw1p1/sunxi_private.h
+++ b/plat/sun50iw1p1/sunxi_private.h
@@ -33,6 +33,7 @@
#include <bl_common.h>
#include <platform_def.h>
+#include "sunxi_power.h"
/*******************************************************************************
* Forward declarations
@@ -72,11 +73,6 @@ int rsb_read(uint8_t rt_addr, uint8_t addr, uint32_t *val, size_t size);
int rsb_write(uint8_t rt_addr, uint8_t addr, uint32_t val, size_t size);
int sunxi_rsb_init(void);
-/* Declarations for sunxi_power.c */
-int sunxi_pmic_setup(void);
-int sunxi_pmic_read(uint8_t address);
-int sunxi_pmic_write(uint8_t address, uint8_t value);
-
void udelay(unsigned int delay);
int sunxi_setup_clocks(uint16_t socid);
void sun50i_set_cpu_pll(unsigned int freq_mhz);