[U-Boot] [PATCH 1/2 RFT] sunxi: power: Add AXP806 and AXP808 support

Chen-Yu Tsai wens at csie.org
Mon Feb 27 03:26:33 UTC 2017


On Mon, Feb 27, 2017 at 3:01 AM, Rask Ingemann Lambertsen
<rask at formelder.dk> wrote:
> An X-Powers AXP806 or AXP808 PMIC is usually found on boards using the
> Allwinner A80 ARM SoC. This patch adds support for the PMIC's regulators
> and sets up the runtime address and master/slave mode in pmic_bus_init().
>
> AXP806/AXP808 support is enabled by default on all MACH_SUN9I boards.
>
> Because there are boards with both an AXP806 and an AXP809,
> drivers/power/Kconfig and arch/arm/mach-sunxi/pmic_bus.c are changed to
> make it possible to have more than one PMIC enabled at a time.
>
> Signed-off-by: Rask Ingemann Lambertsen <rask at formelder.dk>
> ---
> This patch needs to be tested on the following boards which I don't have:
> Cubietech Cubieboard4
> Merrii A80 Optimus
>
>  arch/arm/include/asm/arch-sunxi/pmic_bus.h |   4 +
>  arch/arm/mach-sunxi/Makefile               |   1 +
>  arch/arm/mach-sunxi/pmic_bus.c             | 107 ++++++++++---
>  board/sunxi/board.c                        |  20 +++
>  drivers/power/Kconfig                      | 226 +++++++++++++++++++++++++++-
>  drivers/power/Makefile                     |   1 +
>  drivers/power/axp806.c                     | 231 +++++++++++++++++++++++++++++
>  include/axp806.h                           |  50 +++++++
>  include/axp_pmic.h                         |  13 ++
>  9 files changed, 623 insertions(+), 30 deletions(-)
>  create mode 100644 drivers/power/axp806.c
>  create mode 100644 include/axp806.h
>
> diff --git a/arch/arm/include/asm/arch-sunxi/pmic_bus.h b/arch/arm/include/asm/arch-sunxi/pmic_bus.h
> index 9c4372a..d143d54 100644
> --- a/arch/arm/include/asm/arch-sunxi/pmic_bus.h
> +++ b/arch/arm/include/asm/arch-sunxi/pmic_bus.h
> @@ -14,5 +14,9 @@ int pmic_bus_read(u8 reg, u8 *data);
>  int pmic_bus_write(u8 reg, u8 data);
>  int pmic_bus_setbits(u8 reg, u8 bits);
>  int pmic_bus_clrbits(u8 reg, u8 bits);
> +int pmic2_bus_read(u8 reg, u8 *data);
> +int pmic2_bus_write(u8 reg, u8 data);
> +int pmic2_bus_setbits(u8 reg, u8 bits);
> +int pmic2_bus_clrbits(u8 reg, u8 bits);
>
>  #endif
> diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
> index 7daba11..410fb49 100644
> --- a/arch/arm/mach-sunxi/Makefile
> +++ b/arch/arm/mach-sunxi/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_MACH_SUN9I)      += clock_sun9i.o gtbus_sun9i.o
>  obj-$(CONFIG_AXP152_POWER)     += pmic_bus.o
>  obj-$(CONFIG_AXP209_POWER)     += pmic_bus.o
>  obj-$(CONFIG_AXP221_POWER)     += pmic_bus.o
> +obj-$(CONFIG_AXP806_POWER)     += pmic_bus.o
>  obj-$(CONFIG_AXP809_POWER)     += pmic_bus.o
>  obj-$(CONFIG_AXP818_POWER)     += pmic_bus.o
>
> diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
> index 7c57f02..a2da40c 100644
> --- a/arch/arm/mach-sunxi/pmic_bus.c
> +++ b/arch/arm/mach-sunxi/pmic_bus.c
> @@ -27,6 +27,15 @@
>  #define AXP223_DEVICE_ADDR             0x3a3
>  #define AXP223_RUNTIME_ADDR            0x2d
>
> +/* AXP806 and AXP808 use the same addresses. */
> +#define AXP806_DEVICE_ADDR             0x745
> +#define AXP806_RUNTIME_ADDR            0x3a
> +
> +/* AXP806 and AXP808 address space extension. */
> +#define AXP806_REG_ADDR_EXT                    0xff
> +#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE   0
> +#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE    BIT(4)
> +
>  int pmic_bus_init(void)
>  {
>         /* This cannot be 0 because it is used in SPL before BSS is ready */
> @@ -36,7 +45,8 @@ int pmic_bus_init(void)
>         if (!needs_init)
>                 return 0;
>
> -#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
> +#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP806_POWER || \
> +       defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
>  # ifdef CONFIG_MACH_SUN6I
>         p2wi_init();
>         ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
> @@ -46,16 +56,70 @@ int pmic_bus_init(void)
>         if (ret)
>                 return ret;
>
> +#  if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
> +       defined CONFIG_AXP818_POWER
>         ret = rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
> -# endif
>         if (ret)
>                 return ret;
> +#  endif
> +#  ifdef CONFIG_AXP806_POWER
> +       ret = rsb_set_device_address(AXP806_DEVICE_ADDR, AXP806_RUNTIME_ADDR);
> +       if (ret)
> +               return ret;
> +#  endif
> +# endif
> +
> +# ifdef CONFIG_AXP806_POWER
> +       /*
> +        * An AXP806 or AXP808 can be wired for either master mode or slave
> +        * mode. The AXP806_REG_ADDR_EXT register must be set accordingly for
> +        * the chip to repond to access to its other registers.
> +        */
> +#  ifdef CONFIG_AXP806_POWER_SLAVE_MODE
> +       ret = pmic2_bus_write(AXP806_REG_ADDR_EXT,
> +                             AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
> +#  else
> +       ret = pmic2_bus_write(AXP806_REG_ADDR_EXT,
> +                             AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
> +#  endif
> +       if (ret)
> +               return ret;
> +# endif
>  #endif
>
>         needs_init = 0;
>         return 0;
>  }
>
> +#define PMIC_BUS_SETBITS(pmic_bus_read, pmic_bus_write, reg, bits) \
> +{                                              \
> +       int ret;                                \
> +       u8 val;                                 \
> +                                               \
> +       ret = pmic_bus_read(reg, &val);         \
> +       if (ret)                                \
> +               return ret;                     \
> +                                               \
> +       val |= bits;                            \
> +       return pmic_bus_write(reg, val);        \
> +}
> +
> +#define PMIC_BUS_CLRBITS(pmic_bus_read, pmic_bus_write, reg, bits) \
> +{                                              \
> +       int ret;                                \
> +       u8 val;                                 \
> +                                               \
> +       ret = pmic_bus_read(reg, &val);         \
> +       if (ret)                                \
> +               return ret;                     \
> +                                               \
> +       val &= ~bits;                           \
> +       return pmic_bus_write(reg, val);        \
> +}
> +
> +#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
> +       defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
> +       defined CONFIG_AXP818_POWER
>  int pmic_bus_read(u8 reg, u8 *data)
>  {
>  #ifdef CONFIG_AXP152_POWER
> @@ -87,27 +151,26 @@ int pmic_bus_write(u8 reg, u8 data)
>  }
>
>  int pmic_bus_setbits(u8 reg, u8 bits)
> -{
> -       int ret;
> -       u8 val;
> -
> -       ret = pmic_bus_read(reg, &val);
> -       if (ret)
> -               return ret;
> -
> -       val |= bits;
> -       return pmic_bus_write(reg, val);
> -}
> +PMIC_BUS_SETBITS(pmic_bus_read, pmic_bus_write, reg, bits)
>
>  int pmic_bus_clrbits(u8 reg, u8 bits)
> +PMIC_BUS_CLRBITS(pmic_bus_read, pmic_bus_write, reg, bits)
> +#endif
> +
> +#ifdef CONFIG_AXP806_POWER
> +int pmic2_bus_read(u8 reg, u8 *data)
>  {
> -       int ret;
> -       u8 val;
> -
> -       ret = pmic_bus_read(reg, &val);
> -       if (ret)
> -               return ret;
> -
> -       val &= ~bits;
> -       return pmic_bus_write(reg, val);
> +       return rsb_read(AXP806_RUNTIME_ADDR, reg, data);
>  }
> +
> +int pmic2_bus_write(u8 reg, u8 data)
> +{
> +       return rsb_write(AXP806_RUNTIME_ADDR, reg, data);
> +}
> +
> +int pmic2_bus_setbits(u8 reg, u8 bits)
> +PMIC_BUS_SETBITS(pmic2_bus_read, pmic2_bus_write, reg, bits)
> +
> +int pmic2_bus_clrbits(u8 reg, u8 bits)
> +PMIC_BUS_CLRBITS(pmic2_bus_read, pmic2_bus_write, reg, bits)
> +#endif

Please split the pmic_bus changes into separate patches, such as the following:

  - Pull out PMIC_BUS_*. However please don't use macros. Just make some
    static functions. The compiler can choose to inline them.

  - Add AXP806 support in master mode

  - Add support for second PMIC to pmic_bus

  - Add AXP806 slave mode support.

> diff --git a/board/sunxi/board.c b/board/sunxi/board.c
> index 5365638..7847837 100644
> --- a/board/sunxi/board.c
> +++ b/board/sunxi/board.c
> @@ -540,6 +540,26 @@ void sunxi_board_init(void)
>         power_failed |= axp_set_sw(IS_ENABLED(CONFIG_AXP_SW_ON));
>  #endif
>  #endif
> +#ifdef CONFIG_AXP806_POWER
> +       power_failed |= axp2_init();
> +
> +       power_failed |= axp_set_dcdca(CONFIG_AXP_DCDCA_VOLT);
> +       power_failed |= axp_set_dcdcb(CONFIG_AXP_DCDCB_VOLT);
> +       power_failed |= axp_set_dcdcc(CONFIG_AXP_DCDCC_VOLT);
> +       power_failed |= axp_set_dcdcd(CONFIG_AXP_DCDCD_VOLT);
> +       power_failed |= axp_set_dcdce(CONFIG_AXP_DCDCE_VOLT);
> +       power_failed |= axp2_set_aldo(1, CONFIG_AXP2_ALDO1_VOLT);
> +       power_failed |= axp2_set_aldo(2, CONFIG_AXP2_ALDO2_VOLT);
> +       power_failed |= axp2_set_aldo(3, CONFIG_AXP2_ALDO3_VOLT);

Allwinner code calls them s_aldo.

> +       power_failed |= axp_set_bldo(1, CONFIG_AXP_BLDO1_VOLT);
> +       power_failed |= axp_set_bldo(2, CONFIG_AXP_BLDO2_VOLT);
> +       power_failed |= axp_set_bldo(3, CONFIG_AXP_BLDO3_VOLT);
> +       power_failed |= axp_set_bldo(4, CONFIG_AXP_BLDO4_VOLT);
> +       power_failed |= axp_set_cldo(1, CONFIG_AXP_CLDO1_VOLT);
> +       power_failed |= axp_set_cldo(2, CONFIG_AXP_CLDO2_VOLT);
> +       power_failed |= axp_set_cldo(3, CONFIG_AXP_CLDO3_VOLT);
> +       power_failed |= axp2_set_sw(IS_ENABLED(CONFIG_AXP2_SW_ON));

And this s_sw.

> +#endif
>         printf("DRAM:");
>         ramsize = sunxi_dram_init();
>         printf(" %d MiB\n", (int)(ramsize >> 20));
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index f2c5629..aa32e5a 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -6,19 +6,18 @@ source "drivers/power/pmic/Kconfig"
>
>  source "drivers/power/regulator/Kconfig"
>
> -choice
> -       prompt "Select Sunxi PMIC Variant"
> -       depends on ARCH_SUNXI
> -       default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
> -       default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
> -       default AXP818_POWER if MACH_SUN8I_A83T
> -       default SUNXI_NO_PMIC if MACH_SUN8I_H3 || MACH_SUN50I
> +if ARCH_SUNXI
> +
> +comment "Select Sunxi PMIC Variant"

Would this change break existing defconfigs?

>
>  config SUNXI_NO_PMIC
>         bool "board without a pmic"
> +       default MACH_SUN8I_H3 || MACH_SUN50I
>         ---help---
>         Select this for boards which do not use a PMIC.
>
> +if !SUNXI_NO_PMIC
> +
>  config AXP152_POWER
>         bool "axp152 pmic support"
>         depends on MACH_SUN5I
> @@ -30,6 +29,7 @@ config AXP152_POWER
>  config AXP209_POWER
>         bool "axp209 pmic support"
>         depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
> +       default MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
>         select CMD_POWEROFF
>         ---help---
>         Select this to enable support for the axp209 pmic found on most
> @@ -38,11 +38,31 @@ config AXP209_POWER
>  config AXP221_POWER
>         bool "axp221 / axp223 pmic support"
>         depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
> +       default MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
>         select CMD_POWEROFF
>         ---help---
>         Select this to enable support for the axp221/axp223 pmic found on most
>         A23 and A31 boards.
>
> +config AXP806_POWER
> +       bool "axp806 / axp808 pmic support"
> +       depends on MACH_SUN9I
> +       default MACH_SUN9I
> +       select CMD_POWEROFF
> +       ---help---
> +       Say y here to enable support for the axp806 or axp808 pmic found
> +       on A80 boards.
> +
> +config AXP806_POWER_SLAVE_MODE
> +       bool "axp806 / axp808 pmic slave mode"
> +       depends on AXP806_POWER
> +       default AXP806_POWER && AXP809_POWER
> +       ---help---
> +       Say y here to address an axp806 / axp808 in slave mode.
> +       This is used on all currently supported boards with both an axp806
> +       and an axp809. You should probably say n here if your board only has
> +       an axp806 or axp808.
> +
>  config AXP809_POWER
>         bool "axp809 pmic support"
>         depends on MACH_SUN9I
> @@ -53,6 +73,7 @@ config AXP809_POWER
>  config AXP818_POWER
>         bool "axp818 pmic support"
>         depends on MACH_SUN8I_A83T
> +       default MACH_SUN8I_A83T

>         select CMD_POWEROFF
>         ---help---
>         Say y here to enable support for the axp818 pmic found on
> @@ -65,7 +86,9 @@ config SY8106A_POWER
>         Select this to enable support for the SY8106A pmic found on some
>         H3 boards.
>
> -endchoice
> +endif
> +
> +endif
>
>  config AXP_DCDC1_VOLT
>         int "axp pmic dcdc1 voltage"
> @@ -141,6 +164,63 @@ config AXP_DCDC5_VOLT
>         On A23 / A31 / A33 / A80 / A83T boards dcdc5 is VCC-DRAM and
>         should be 1.5V, 1.35V if DDR3L is used.
>
> +config AXP_DCDCA_VOLT
> +       int "axp pmic dcdca voltage"
> +       depends on AXP806_POWER
> +       default 900 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic dcdca at, set to 0 to
> +       disable dcdca.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdca
> +       powers the Cortex-A15 cores (VDD-CPUB) and should be 0.9 V.
> +       On the Sunchip CX-A99 board, dcdca powers the Cortex-A7 cores
> +       (VDD-CPUA) and should be 0.9 V at the default 1008 MHz clock frequency.

Don't mention board names. Instead you could say boards with 2 PMICs with AXP806
in slave mode do A, and boards with only one PMIC do B.

> +
> +config AXP_DCDCB_VOLT
> +       int "axp pmic dcdcb voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 1500 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER

!AXP806_POWER_SLAVE_MODE would be better

> +       ---help---
> +       Set the voltage (mV) to program the axp pmic dcdcb at, set to 0 to
> +       disable dcdcb.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdcb
> +       is unused and can be left off.
> +       On the Sunchip CX-A99 board, dcdcb powers VCC-DRAM and should be 1.5 V.
> +
> +config AXP_DCDCC_VOLT
> +       int "axp pmic dcdcc voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic dcdcc at, set to 0 to
> +       disable dcdcc.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdcb
> +       is unused and can be left off.
> +       On the Sunchip CX-A99 board, dcdcc powers VDD-GPU and can be left off.
> +
> +config AXP_DCDCD_VOLT
> +       int "axp pmic dcdcd voltage"
> +       depends on AXP806_POWER
> +       default 900 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic dcdcd at, set to 0 to
> +       disable dcdcd.
> +       On A80 boards dcdcd powers VDD-SYS or VDD-VPU and should be 0.9 V.
> +
> +config AXP_DCDCE_VOLT
> +       int "axp pmic dcdce voltage"
> +       depends on AXP806_POWER
> +       default 2100 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 3300 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic dcdce at, set to 0 to
> +       disable dcdce.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdce
> +       should be 2.1 V.
> +       On the Sunchip CX-A99, dcdce powers several parts which need 3.3 V,
> +       such as pin groups B-F and H, the eMMC card and the SD card slot.
> +
>  config AXP_ALDO1_VOLT
>         int "axp pmic (a)ldo1 voltage"
>         depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
> @@ -197,6 +277,126 @@ config AXP_ALDO4_VOLT
>         disable aldo4.
>         On A10(s) / A13 / A20 boards aldo4 should be 2.8V.
>
> +config AXP2_ALDO1_VOLT
> +       int "axp pmic (2) aldo1 voltage"
> +       depends on AXP806_POWER
> +       default 3000 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 0 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to
> +       disable aldo1.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo1
> +       powers AVCC and should be 3.0 V.
> +       On the Sunchip CX-A99, it is unknown what aldo1 powers and it can be
> +       left off.
> +
> +config AXP2_ALDO2_VOLT
> +       int "axp pmic (2) aldo2 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 1800 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to
> +       disable aldo2.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo2 is
> +       unused and can be left off.
> +       On the Sunchip CX-A99, aldo2 powers pin groups G and M, Wifi I/O and
> +       codec I/O and should be 1.8 V.

These pins are not used by U-boot are they? Leave them off.

> +
> +config AXP2_ALDO3_VOLT
> +       int "axp pmic (2) aldo3 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to
> +       disable aldo3.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo3 is
> +       unused and can be left off.
> +       On the Sunchip CX-A99, aldo3 powers GMAC 2.5 V I/O and can be left off.
> +
> +config AXP_BLDO1_VOLT
> +       int "axp pmic bldo1 voltage"
> +       depends on AXP806_POWER
> +       default 1800 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic bldo1 at, set to 0 to
> +       disable bldo1.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo1
> +       powers efuse, ADC, display and camera interface and should be 1.8 V.
> +       On the Sunchip CX-A99, bldo1 powers A80 DLLs and PLLs and should be
> +       1.8 V.
> +
> +config AXP_BLDO2_VOLT
> +       int "axp pmic bldo2 voltage"
> +       depends on AXP806_POWER
> +       default 1800 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 900 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic bldo2 at, set to 0 to
> +       disable bldo2.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo2
> +       powers PLLs which need 1.8 V.
> +       On the Sunchip CX-A99, bldo2 powers A80 subsystems which need 0.9 V.
> +
> +config AXP_BLDO3_VOLT
> +       int "axp pmic bldo3 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic bldo3 at, set to 0 to
> +       disable bldo3.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo3 is
> +       unused and can be left off.
> +       On the Sunchip CX-A99, bldo2 powers the unused USB HSIC interface and
> +       can be left off.
> +
> +config AXP_BLDO4_VOLT
> +       int "axp pmic bldo4 voltage"
> +       depends on AXP806_POWER
> +       default 1800 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 0 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic bldo4 at, set to 0 to
> +       disable bldo4.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo4
> +       powers VCC12-HSIC and should be 1.2 V.
> +       On the Sunchip CX-A99, bldo powers VDD09-HDMI and can be left off.
> +
> +config AXP_CLDO1_VOLT
> +       int "axp pmic cldo1 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
> +       default 3300 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic cldo at, set to 0 to
> +       disable cldo.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo1
> +       supplies the unsupported GMAC 3.3 V and can be left off.
> +       On the Sunchip CX-A99, cldo1 powers pin group L and the LEDs and
> +       should be 3.3 V.
> +
> +config AXP_CLDO2_VOLT
> +       int "axp pmic cldo2 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic cldo2 at, set to 0 to
> +       disable cldo2.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo2
> +       powers the camera and can be left off.
> +       On the Sunchip CX-A99, cldo2 powers Wifi+Bluetooth and can be left off.
> +
> +config AXP_CLDO3_VOLT
> +       int "axp pmic cldo3 voltage"
> +       depends on AXP806_POWER
> +       default 0 if MACH_SUN9I
> +       ---help---
> +       Set the voltage (mV) to program the axp pmic cldo3 at, set to 0 to
> +       disable cldo3.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo3
> +       powers Wifi I/O and codec I/O and can be left off.
> +       On the Sunchip CX-A99, cldo3 powers Wifi+Bluetooth and can be left off.
> +
>  config AXP_DLDO1_VOLT
>         int "axp pmic dldo1 voltage"
>         depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
> @@ -295,6 +495,16 @@ config AXP_SW_ON
>         ---help---
>         Enable to turn on axp pmic sw.
>
> +config AXP2_SW_ON
> +       bool "axp pmic (2) sw on"
> +       depends on AXP806_POWER
> +       default n
> +       ---help---
> +       Enable to turn on axp pmic sw.
> +       On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, sw is unused
> +       and can be left off.
> +       On the Sunchip CX-A99, sw powers GMAC and codec and can be left off.
> +
>  config SY8106A_VOUT1_VOLT
>         int "SY8106A pmic VOUT1 voltage"
>         depends on SY8106A_POWER
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index b43523e..aaf8248 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_AS3722_POWER)      += as3722.o
>  obj-$(CONFIG_AXP152_POWER)     += axp152.o
>  obj-$(CONFIG_AXP209_POWER)     += axp209.o
>  obj-$(CONFIG_AXP221_POWER)     += axp221.o
> +obj-$(CONFIG_AXP806_POWER)     += axp806.o
>  obj-$(CONFIG_AXP809_POWER)     += axp809.o
>  obj-$(CONFIG_AXP818_POWER)     += axp818.o
>  obj-$(CONFIG_EXYNOS_TMU)       += exynos-tmu.o
> diff --git a/drivers/power/axp806.c b/drivers/power/axp806.c
> new file mode 100644
> index 0000000..be6a9a8
> --- /dev/null
> +++ b/drivers/power/axp806.c
> @@ -0,0 +1,231 @@
> +/*
> + * AXP806 and AXP808 driver based on AXP221 and AXP223 driver
> + *
> + * Copyright (C) 2017 Rask Ingemann Lambertsen <rask at formelder.dk>
> + *
> + * Based on axp221.c which is
> + * (C) Copyright 2014 Hans de Goede <hdegoede at redhat.com>
> + * (C) Copyright 2013 Oliver Schinagl <oliver at schinagl.nl>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <errno.h>
> +#include <asm/arch/pmic_bus.h>
> +#include <axp_pmic.h>
> +
> +/*
> + * Return cfg for a regulator with a linear range from `min' to `max' in steps
> + * of `div' and an optional second linear range from `max' to `max2' in steps
> + * of `div2'. Pass `max2' == `max' and `div2' == `div' for a single range.
> + */
> +static u8 axp_mvolt_to_cfg(int mvolt, int min, int max, int div,
> +                          int max2, int div2)
> +{
> +       if (mvolt < min) {
> +               mvolt = min;
> +       } else if (mvolt > max) {
> +               if (mvolt > max2)
> +                       mvolt = max2;
> +               return (mvolt - max) / div2 + (max - min) / div;
> +       }
> +       return (mvolt - min) / div;
> +}
> +
> +int axp_set_dcdca(unsigned int mvolt)
> +{
> +       int ret;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1100, 10, 1520, 20);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_DCDCA_EN);
> +
> +       ret = pmic2_bus_write(AXP806_DCDCA_CTRL, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_DCDCA_EN);
> +}
> +
> +int axp_set_dcdcb(unsigned int mvolt)
> +{
> +       int ret;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 1000, 2550, 50, 2550, 50);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_DCDCB_EN);
> +
> +       ret = pmic2_bus_write(AXP806_DCDCB_CTRL, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_DCDCB_EN);
> +}
> +
> +int axp_set_dcdcc(unsigned int mvolt)
> +{
> +       int ret;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1100, 10, 1520, 20);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_DCDCC_EN);
> +
> +       ret = pmic2_bus_write(AXP806_DCDCC_CTRL, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_DCDCC_EN);
> +}
> +
> +int axp_set_dcdcd(unsigned int mvolt)
> +{
> +       int ret;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1500, 20, 3300, 100);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_DCDCD_EN);
> +
> +       ret = pmic2_bus_write(AXP806_DCDCD_CTRL, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_DCDCD_EN);
> +}
> +
> +int axp_set_dcdce(unsigned int mvolt)
> +{
> +       int ret;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 1100, 3400, 100, 3400, 100);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_DCDCE_EN);
> +
> +       ret = pmic2_bus_write(AXP806_DCDCE_CTRL, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_DCDCE_EN);
> +}
> +
> +int axp2_set_aldo(int ldo_num, unsigned int mvolt)
> +{
> +       int ret;
> +       unsigned int ldo = ldo_num - 1;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 700, 3300, 100, 3300, 100);
> +
> +       if (ldo_num < 1 || ldo_num > 3)
> +               return -EINVAL;
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
> +                                        AXP806_OUTPUT_CTRL1_ALDO1_EN << ldo);
> +
> +       ret = pmic2_bus_write(AXP806_ALDO1_CTRL + ldo, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
> +                                AXP806_OUTPUT_CTRL1_ALDO1_EN << ldo);
> +}
> +
> +int axp_set_bldo(int ldo_num, unsigned int mvolt)
> +{
> +       int ret;
> +       unsigned int ldo = ldo_num - 1;
> +       u8 cfg = axp_mvolt_to_cfg(mvolt, 700, 1900, 100, 1900, 100);
> +
> +       if (ldo_num < 1 || ldo_num > 4)
> +               return -EINVAL;
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
> +                                       AXP806_OUTPUT_CTRL2_BLDO1_EN << ldo);
> +
> +       ret = pmic2_bus_write(AXP806_BLDO1_CTRL + ldo, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
> +                               AXP806_OUTPUT_CTRL2_BLDO1_EN << ldo);
> +}
> +
> +int axp_set_cldo(int ldo_num, unsigned int mvolt)
> +{
> +       int ret;
> +       unsigned int ldo = ldo_num - 1;
> +       u8 cfg;
> +
> +       if (ldo_num < 1 || ldo_num > 3)
> +               return -EINVAL;
> +
> +       if (ldo_num == 2)
> +               cfg = axp_mvolt_to_cfg(mvolt, 700, 3400, 100, 4200, 200);
> +       else
> +               cfg = axp_mvolt_to_cfg(mvolt, 700, 3300, 100, 3300, 100);
> +
> +       if (mvolt == 0)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
> +                                       AXP806_OUTPUT_CTRL2_CLDO1_EN << ldo);
> +
> +       ret = pmic2_bus_write(AXP806_CLDO1_CTRL + ldo, cfg);
> +       if (ret)
> +               return ret;
> +
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
> +                               AXP806_OUTPUT_CTRL2_CLDO1_EN << ldo);
> +}
> +
> +int axp2_set_sw(bool on)
> +{
> +       if (!on)
> +               return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
> +                                       AXP806_OUTPUT_CTRL2_SW_EN);
> +       return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
> +                               AXP806_OUTPUT_CTRL2_SW_EN);
> +}
> +
> +int axp2_init(void)
> +{
> +       u8 axp_chip_id;
> +       int ret;
> +
> +       ret = pmic_bus_init();
> +       if (ret)
> +               return ret;
> +
> +       ret = pmic2_bus_read(AXP806_CHIP_ID, &axp_chip_id);
> +       if (ret)
> +               return ret;
> +
> +       if ((axp_chip_id & 0xcf) != 0x40)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +/* The AXP809 driver also implements do_poweroff() and we can't have both. */
> +#ifndef CONFIG_AXP809_POWER

Use CONFIG_AXP806_POWER_SLAVE_MODE. System power would be controlled by the
master PMIC.

Regards
ChenYu

> +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       pmic2_bus_setbits(AXP806_SHUTDOWN_CTRL, AXP806_SHUTDOWN_POWEROFF);
> +
> +       /* infinite loop during shutdown */
> +       while (1)
> +               ;
> +
> +       /* not reached */
> +       return 0;
> +}
> +#endif
> diff --git a/include/axp806.h b/include/axp806.h
> new file mode 100644
> index 0000000..d7f7f2b
> --- /dev/null
> +++ b/include/axp806.h
> @@ -0,0 +1,50 @@
> +/*
> + * X-Powers AXP806 and AXP808 Power Management IC driver
> + *
> + * Copyright (C) 2017 Rask Ingemann Lambertsen <rask at formelder.dk>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <linux/bitops.h>
> +
> +#define AXP806_CHIP_ID         0x03
> +#define AXP806_OUTPUT_CTRL1    0x10
> +#define AXP806_OUTPUT_CTRL2    0x11
> +#define AXP806_DCDCA_CTRL      0x12
> +#define AXP806_DCDCB_CTRL      0x13
> +#define AXP806_DCDCC_CTRL      0x14
> +#define AXP806_DCDCD_CTRL      0x15
> +#define AXP806_DCDCE_CTRL      0x16
> +#define AXP806_ALDO1_CTRL      0x17
> +#define AXP806_ALDO2_CTRL      0x18
> +#define AXP806_ALDO3_CTRL      0x19
> +/* Unused registers here. */
> +#define AXP806_BLDO1_CTRL      0x20
> +#define AXP806_BLDO2_CTRL      0x21
> +#define AXP806_BLDO3_CTRL      0x22
> +#define AXP806_BLDO4_CTRL      0x23
> +#define AXP806_CLDO1_CTRL      0x24
> +#define AXP806_CLDO2_CTRL      0x25
> +#define AXP806_CLDO3_CTRL      0x26
> +#define AXP806_SHUTDOWN_CTRL   0x32
> +
> +#define AXP806_OUTPUT_CTRL1_DCDCA_EN   BIT(0)
> +#define AXP806_OUTPUT_CTRL1_DCDCB_EN   BIT(1)
> +#define AXP806_OUTPUT_CTRL1_DCDCC_EN   BIT(2)
> +#define AXP806_OUTPUT_CTRL1_DCDCD_EN   BIT(3)
> +#define AXP806_OUTPUT_CTRL1_DCDCE_EN   BIT(4)
> +#define AXP806_OUTPUT_CTRL1_ALDO1_EN   BIT(5)
> +#define AXP806_OUTPUT_CTRL1_ALDO2_EN   BIT(6)
> +#define AXP806_OUTPUT_CTRL1_ALDO3_EN   BIT(7)
> +
> +#define AXP806_OUTPUT_CTRL2_BLDO1_EN   BIT(0)
> +#define AXP806_OUTPUT_CTRL2_BLDO2_EN   BIT(1)
> +#define AXP806_OUTPUT_CTRL2_BLDO3_EN   BIT(2)
> +#define AXP806_OUTPUT_CTRL2_BLDO4_EN   BIT(3)
> +#define AXP806_OUTPUT_CTRL2_CLDO1_EN   BIT(4)
> +#define AXP806_OUTPUT_CTRL2_CLDO2_EN   BIT(5)
> +#define AXP806_OUTPUT_CTRL2_CLDO3_EN   BIT(6)
> +#define AXP806_OUTPUT_CTRL2_SW_EN      BIT(7)
> +
> +#define AXP806_SHUTDOWN_POWEROFF       BIT(7)
> diff --git a/include/axp_pmic.h b/include/axp_pmic.h
> index d789ad8..7d5dad7 100644
> --- a/include/axp_pmic.h
> +++ b/include/axp_pmic.h
> @@ -16,6 +16,9 @@
>  #ifdef CONFIG_AXP221_POWER
>  #include <axp221.h>
>  #endif
> +#ifdef CONFIG_AXP806_POWER
> +#include <axp806.h>
> +#endif
>  #ifdef CONFIG_AXP809_POWER
>  #include <axp809.h>
>  #endif
> @@ -28,15 +31,25 @@ int axp_set_dcdc2(unsigned int mvolt);
>  int axp_set_dcdc3(unsigned int mvolt);
>  int axp_set_dcdc4(unsigned int mvolt);
>  int axp_set_dcdc5(unsigned int mvolt);
> +int axp_set_dcdca(unsigned int mvolt);
> +int axp_set_dcdcb(unsigned int mvolt);
> +int axp_set_dcdcc(unsigned int mvolt);
> +int axp_set_dcdcd(unsigned int mvolt);
> +int axp_set_dcdce(unsigned int mvolt);
>  int axp_set_aldo1(unsigned int mvolt);
>  int axp_set_aldo2(unsigned int mvolt);
>  int axp_set_aldo3(unsigned int mvolt);
>  int axp_set_aldo4(unsigned int mvolt);
> +int axp2_set_aldo(int aldo_num, unsigned int mvolt);
> +int axp_set_bldo(int bldo_num, unsigned int mvolt);
> +int axp_set_cldo(int cldo_num, unsigned int mvolt);
>  int axp_set_dldo(int dldo_num, unsigned int mvolt);
>  int axp_set_eldo(int eldo_num, unsigned int mvolt);
>  int axp_set_fldo(int fldo_num, unsigned int mvolt);
>  int axp_set_sw(bool on);
> +int axp2_set_sw(bool on);
>  int axp_init(void);
> +int axp2_init(void);
>  int axp_get_sid(unsigned int *sid);
>
>  #endif
> --
> 2.10.2
>


More information about the U-Boot mailing list