diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 480269fa60..1da6bf613b 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -744,7 +744,8 @@ dtb-$(CONFIG_MACH_SUN50I_H6) += \ sun50i-h6-tanix-tx6-mini.dtb dtb-$(CONFIG_MACH_SUN50I_H616) += \ sun50i-h616-orangepi-zero2.dtb \ - sun50i-h616-x96-mate.dtb + sun50i-h616-x96-mate.dtb \ + sun50i-h616-mangopi-mq-quad.dtb dtb-$(CONFIG_MACH_SUN50I) += \ sun50i-a64-amarula-relic.dtb \ sun50i-a64-bananapi-m64.dtb \ diff --git a/arch/arm/dts/sun50i-h616-mangopi-mq-quad.dts b/arch/arm/dts/sun50i-h616-mangopi-mq-quad.dts new file mode 100644 index 0000000000..81f87f1f0b --- /dev/null +++ b/arch/arm/dts/sun50i-h616-mangopi-mq-quad.dts @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2020 Arm Ltd. + */ + +/dts-v1/; + +#include "sun50i-h616.dtsi" + +#include +#include +#include + +/ { + model = "MangoPi MQ-Quad"; + compatible = "allwinner,sun50i-h616"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */ + }; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the USB-C socket */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_vcc3v3: vcc3v3 { + /* board wide 3V3 supply directly from SY8008 regulator */ + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; +}; + +&ehci1 { + status = "okay"; +}; + +/* USB 2 & 3 are on headers only. */ + +&mmc0 { + vmmc-supply = <®_vcc3v3>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + bus-width = <4>; + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&r_i2c { + status = "okay"; + + axp313a: pmic@36 { + compatible = "x-powers,axp313a"; + reg = <0x36>; + x-powers,self-working-mode; + regulators { + reg_aldo1: aldo1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-1v8"; + }; + + reg_dldo1: dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-3v3-pmic"; + }; + + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <990000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-cpu"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-name = "vdd-dram"; + }; + + }; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; + status = "okay"; +}; + +&usbotg { + /* + * PHY0 pins are connected to a USB-C socket, but a role switch + * is not implemented: both CC pins are pulled to GND. + * The VBUS pins power the device, so a fixed peripheral mode + * is the best choice. + * The board can be powered via GPIOs, in this case port0 *can* + * act as a host (with a cable/adapter ignoring CC), as VBUS is + * then provided by the GPIOs. Any user of this setup would + * need to adjust the DT accordingly: dr_mode set to "host", + * enabling OHCI0 and EHCI0. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + usb1_vbus-supply = <®_vcc5v>; + status = "okay"; +}; diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c index c090840637..3e7bb5a5d1 100644 --- a/arch/arm/mach-sunxi/pmic_bus.c +++ b/arch/arm/mach-sunxi/pmic_bus.c @@ -21,7 +21,7 @@ #define AXP209_I2C_ADDR 0x34 -#define AXP305_I2C_ADDR 0x36 +#define AXP305_I2C_ADDR 0x36 /* AXP305 and AXP313A */ #define AXP221_CHIP_ADDR 0x68 @@ -32,7 +32,7 @@ static int pmic_i2c_address(void) { if (IS_ENABLED(CONFIG_AXP152_POWER)) return AXP152_I2C_ADDR; - if (IS_ENABLED(CONFIG_AXP305_POWER)) + if (IS_ENABLED(CONFIG_AXP305_POWER) || IS_ENABLED(CONFIG_AXP313A_POWER)) return AXP305_I2C_ADDR; /* Other AXP2xx and AXP8xx variants */ diff --git a/board/sunxi/board.c b/board/sunxi/board.c index f321cd58a6..9b0069cd52 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -584,6 +584,7 @@ void sunxi_board_init(void) #if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \ defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \ + defined CONFIG_AXP313A_POWER || \ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER power_failed = axp_init(); @@ -605,7 +606,8 @@ void sunxi_board_init(void) power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT); power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT); #endif -#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER) +#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER) && \ + !defined(CONFIG_AXP313A_POWER) power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT); #endif #if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \ @@ -617,10 +619,11 @@ void sunxi_board_init(void) defined CONFIG_AXP818_POWER power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT); #endif -#if !defined(CONFIG_AXP305_POWER) +#if !defined(CONFIG_AXP305_POWER) && !defined(CONFIG_AXP313A_POWER) power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT); #endif -#if !defined(CONFIG_AXP152_POWER) && !defined(CONFIG_AXP305_POWER) +#if !defined(CONFIG_AXP152_POWER) && !defined(CONFIG_AXP305_POWER) && \ + !defined(CONFIG_AXP313A_POWER) power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT); #endif #ifdef CONFIG_AXP209_POWER diff --git a/configs/mangopi_mq_quad_defconfig b/configs/mangopi_mq_quad_defconfig new file mode 100644 index 0000000000..80272101a9 --- /dev/null +++ b/configs/mangopi_mq_quad_defconfig @@ -0,0 +1,18 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="sun50i-h616-mangopi-mq-quad" +CONFIG_SPL=y +CONFIG_DRAM_SUN50I_H616_DX_ODT=0x08080808 +CONFIG_DRAM_SUN50I_H616_DX_DRI=0x0e0e0e0e +CONFIG_DRAM_SUN50I_H616_CA_DRI=0x0e0e +CONFIG_DRAM_SUN50I_H616_TPR10=0xf83438 +CONFIG_MACH_SUN50I_H616=y +CONFIG_R_I2C_ENABLE=y +CONFIG_SPL_SPI_SUNXI=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C=y +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SYS_I2C_SLAVE=0x7f +CONFIG_SYS_I2C_SPEED=400000 +CONFIG_AXP313A_POWER=y diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 7f3b990d23..3fb78295d5 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -101,6 +101,14 @@ config AXP305_POWER Select this to enable support for the axp305 pmic found on most H616 boards. +config AXP313A_POWER + bool "axp313a pmic support" + select AXP_PMIC_BUS + select CMD_POWEROFF + ---help--- + Select this to enable support for the axp313a pmic found on some + H616 boards. + config AXP809_POWER bool "axp809 pmic support" depends on MACH_SUN9I @@ -143,8 +151,8 @@ config AXP_DCDC1_VOLT config AXP_DCDC2_VOLT int "axp pmic dcdc2 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER - default 900 if AXP818_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313A_POWER + default 900 if AXP818_POWER || AXP313A_POWER default 1400 if AXP152_POWER || AXP209_POWER default 1200 if MACH_SUN6I default 1100 if MACH_SUN8I @@ -161,9 +169,9 @@ config AXP_DCDC2_VOLT config AXP_DCDC3_VOLT int "axp pmic dcdc3 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313A_POWER default 900 if AXP809_POWER || AXP818_POWER - default 1500 if AXP152_POWER + default 1500 if AXP152_POWER || AXP313A_POWER default 1250 if AXP209_POWER default 1100 if MACH_SUN8I_R40 default 1200 if MACH_SUN6I || MACH_SUN8I diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ba64b2c593..f851f4a94e 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_AXP152_POWER) += axp152.o obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_AXP221_POWER) += axp221.o obj-$(CONFIG_AXP305_POWER) += axp305.o +obj-$(CONFIG_AXP313A_POWER) += axp313a.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/axp313a.c b/drivers/power/axp313a.c new file mode 100644 index 0000000000..a344bac90f --- /dev/null +++ b/drivers/power/axp313a.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AXP313A driver based on AXP221 driver + * + * + * (C) Copyright 2023 SASANO Takayoshi + * + * Based on axp221.c + * (C) Copyright 2014 Hans de Goede + * (C) Copyright 2013 Oliver Schinagl + */ + +#include +#include +#include +#include +#include + +static u8 axp313a_mvolt_to_cfg(int mvolt, int min, int max, int div) +{ + if (mvolt < min) + mvolt = min; + else if (mvolt > max) + mvolt = max; + + return (mvolt - min) / div; +} + +int axp_set_dcdc1(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1600) + cfg = 88 + axp313a_mvolt_to_cfg(mvolt, 1600, 3400, 100); + else if (mvolt >= 1220) + cfg = 71 + axp313a_mvolt_to_cfg(mvolt, 1220, 1540, 20); + else + cfg = axp313a_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC1); + + ret = pmic_bus_write(AXP313A_DCDC1_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC1); +} + +int axp_set_dcdc2(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 71 + axp313a_mvolt_to_cfg(mvolt, 1220, 1540, 20); + else + cfg = axp313a_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC2); + + ret = pmic_bus_write(AXP313A_DCDC2_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC2); +} + +int axp_set_dcdc3(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 71 + axp313a_mvolt_to_cfg(mvolt, 1220, 1840, 20); + else + cfg = axp313a_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC3); + + ret = pmic_bus_write(AXP313A_DCDC3_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DCDC3); +} + +int axp_set_aldo1(unsigned int mvolt) +{ + int ret; + u8 cfg = axp313a_mvolt_to_cfg(mvolt, 500, 3500, 100); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_ALDO1); + + ret = pmic_bus_write(AXP313A_ALDO1_CTRL, cfg); + if (cfg) + return ret; + + return pmic_bus_setbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_ALDO1); +} + +int axp_set_dldo(int dldo_num, unsigned int mvolt) +{ + int ret; + u8 cfg = axp313a_mvolt_to_cfg(mvolt, 500, 3500, 100); + + if (dldo_num != 1) + return -EINVAL; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DLDO1); + + ret = pmic_bus_write(AXP313A_DLDO1_CTRL, cfg); + if (cfg) + return ret; + + return pmic_bus_setbits(AXP313A_OUTPUT_CTRL, + AXP313A_OUTPUT_CTRL_DLDO1); +} + +int axp_init(void) +{ + int ret; + u8 axp_chip_id; + + ret = pmic_bus_init(); + if (ret) + return ret; + + ret = pmic_bus_read(AXP313A_CHIP_VERSION, &axp_chip_id); + if (ret) + return ret; + + axp_chip_id &= AXP313A_CHIP_VERSION_MASK; + switch (axp_chip_id) { + case AXP313A_CHIP_VERSION_AXP1530: + case AXP313A_CHIP_VERSION_AXP313A: + case AXP313A_CHIP_VERSION_AXP313B: + break; + default: + return -EINVAL; + } + + return ret; +} + +#if !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF) +int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + pmic_bus_write(AXP313A_SHUTDOWN, AXP313A_POWEROFF); + + /* infinite loop during shutdown */ + while (1) {} + + /* not reached */ + return 0; +} +#endif diff --git a/drivers/power/pmic/axp.c b/drivers/power/pmic/axp.c index 025dac24f2..d23c16d996 100644 --- a/drivers/power/pmic/axp.c +++ b/drivers/power/pmic/axp.c @@ -87,6 +87,7 @@ static const struct udevice_id axp_pmic_ids[] = { { .compatible = "x-powers,axp209", .data = AXP209_ID }, { .compatible = "x-powers,axp221", .data = AXP221_ID }, { .compatible = "x-powers,axp223", .data = AXP223_ID }, + { .compatible = "x-powers,axp313a", .data = AXP313A_ID }, { .compatible = "x-powers,axp803", .data = AXP803_ID }, { .compatible = "x-powers,axp806", .data = AXP806_ID }, { .compatible = "x-powers,axp809", .data = AXP809_ID }, diff --git a/include/axp313a.h b/include/axp313a.h new file mode 100644 index 0000000000..a61a11a53c --- /dev/null +++ b/include/axp313a.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2023 SASANO Takayoshi + */ + +enum axp313a_reg { + AXP313A_POWER_STATUS = 0x00, + AXP313A_CHIP_VERSION = 0x03, + AXP313A_OUTPUT_CTRL = 0x10, + AXP313A_DCDC1_CTRL = 0x13, + AXP313A_DCDC2_CTRL = 0x14, + AXP313A_DCDC3_CTRL = 0x15, + AXP313A_ALDO1_CTRL = 0x16, + AXP313A_DLDO1_CTRL = 0x17, + AXP313A_SHUTDOWN = 0x1a, + AXP313A_IRQ_ENABLE = 0x20, + AXP313A_IRQ_STATUS = 0x21, +}; + +#define AXP313A_CHIP_VERSION_MASK 0xcf +#define AXP313A_CHIP_VERSION_AXP1530 0x48 +#define AXP313A_CHIP_VERSION_AXP313A 0x4b +#define AXP313A_CHIP_VERSION_AXP313B 0x4c + +#define AXP313A_OUTPUT_CTRL_DCDC1 BIT(0) +#define AXP313A_OUTPUT_CTRL_DCDC2 BIT(1) +#define AXP313A_OUTPUT_CTRL_DCDC3 BIT(2) +#define AXP313A_OUTPUT_CTRL_ALDO1 BIT(3) +#define AXP313A_OUTPUT_CTRL_DLDO1 BIT(4) + +#define AXP313A_POWEROFF BIT(7) diff --git a/include/axp_pmic.h b/include/axp_pmic.h index 4ac6486583..9b6d7d900c 100644 --- a/include/axp_pmic.h +++ b/include/axp_pmic.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ enum { AXP209_ID, AXP221_ID, AXP223_ID, + AXP313A_ID, AXP803_ID, AXP806_ID, AXP809_ID,