allwinner: sun50i_h6: add initial AXP805 PMIC code
authorIcenowy Zheng <icenowy@aosc.io>
Sun, 22 Jul 2018 13:30:14 +0000 (21:30 +0800)
committerIcenowy Zheng <icenowy@aosc.io>
Fri, 7 Sep 2018 15:20:17 +0000 (23:20 +0800)
The OTT reference design of Allwinner H6 SoC uses an X-Powers AXP805
PMIC.

Add initial code for it.

Currently it's only detected.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
plat/allwinner/sun50i_h6/platform.mk
plat/allwinner/sun50i_h6/sunxi_power.c

index e9ee23d03c79865197ab7f4a14ac3756c8fb2135..c3901d0174836be60ef8cee078c441a2f8b24249 100644 (file)
@@ -7,6 +7,7 @@
 include lib/xlat_tables_v2/xlat_tables.mk
 
 AW_PLAT                        :=      plat/allwinner
+AW_DRIVERS             :=      drivers/allwinner
 
 PLAT_INCLUDES          :=      -Iinclude/plat/arm/common               \
                                -Iinclude/plat/arm/common/aarch64       \
@@ -15,6 +16,7 @@ PLAT_INCLUDES         :=      -Iinclude/plat/arm/common               \
 
 PLAT_BL_COMMON_SOURCES :=      drivers/console/${ARCH}/console.S       \
                                drivers/ti/uart/${ARCH}/16550_console.S \
+                               ${AW_DRIVERS}/sunxi_i2c.c               \
                                ${XLAT_TABLES_LIB_SRCS}                 \
                                ${AW_PLAT}/common/plat_helpers.S        \
                                ${AW_PLAT}/common/sunxi_common.c
index 50eaa6b9d2fd39371ce511e0b7487578540b9a28..3638a199c35bb23b5b792b22bbfbe87a19767191 100644 (file)
  */
 
 #include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <mentor/mi2cv.h>
+#include <string.h>
+#include <sunxi_mmap.h>
+
+#define AXP805_ADDR    0x36
+#define AXP805_ID      0x03
+
+enum pmic_type {
+       NO_PMIC,
+       AXP805,
+};
+
+enum pmic_type pmic;
+
+static int sunxi_init_r_i2c(void)
+{
+       uint32_t reg;
+
+       /* get currently configured function for pins PL0 and PL1 */
+       reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
+       if ((reg & 0xff) == 0x33) {
+               NOTICE("PMIC: already configured for TWI\n");
+       }
+
+       /* switch pins PL0 and PL1 to I2C */
+       mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
+
+       /* level 2 drive strength */
+       reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
+       mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
+
+       /* set both ports to pull-up */
+       reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
+       mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
+
+       /* assert & de-assert reset of R_I2C */
+       reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+       mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
+       reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+       mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
+
+       /* un-gate R_I2C clock */
+       reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+       mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
+
+       /* call mi2cv driver */
+       i2c_init((void *)SUNXI_R_I2C_BASE);
+
+       return 0;
+}
+
+int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
+{
+       int ret;
+
+       ret = i2c_write(chip, 0, 0, &reg, 1);
+       if (ret)
+               return ret;
+
+       return i2c_read(chip, 0, 0, val, 1);
+}
+
+int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
+{
+       return i2c_write(chip, reg, 1, &val, 1);
+}
+
+static int axp805_probe(void)
+{
+       int ret;
+       uint8_t val;
+
+       ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
+       if (ret) {
+               ERROR("PMIC: Cannot put AXP805 to master mode.\n");
+               return -EPERM;
+       }
+
+       ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
+
+       if (!ret && ((val & 0xcf) == 0x40))
+               NOTICE("PMIC: AXP805 detected\n");
+       else if (ret) {
+               ERROR("PMIC: Cannot communicate with AXP805.\n");
+               return -EPERM;
+       } else {
+               ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
 
 int sunxi_pmic_setup(void)
 {
-       /* STUB */
-       NOTICE("BL31: STUB PMIC setup code called\n");
+       int ret;
+
+       sunxi_init_r_i2c();
+
+       NOTICE("PMIC: Probing AXP805\n");
+       pmic = AXP805;
+
+       ret = axp805_probe();
+       if (ret)
+               pmic = NO_PMIC;
+       else
+               pmic = AXP805;
 
        return 0;
 }