On Mon, Feb 27, 2017 at 3:01 AM, Rask Ingemann Lambertsen <r...@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 <r...@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 <r...@formelder.dk> > + * > + * Based on axp221.c which is > + * (C) Copyright 2014 Hans de Goede <hdego...@redhat.com> > + * (C) Copyright 2013 Oliver Schinagl <oli...@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 <r...@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 > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot