diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 480269fa606..f5004f45b9f 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -760,6 +760,7 @@ dtb-$(CONFIG_MACH_SUN50I) += \ sun50i-a64-pinephone-1.0.dtb \ sun50i-a64-pinephone-1.1.dtb \ sun50i-a64-pinephone-1.2.dtb \ + sun50i-a64-pinephone-1.2b.dtb \ sun50i-a64-pinetab.dtb \ sun50i-a64-sopine-baseboard.dtb \ sun50i-a64-teres-i.dtb diff --git a/arch/arm/dts/sun50i-a64-pinephone-1.2b.dts b/arch/arm/dts/sun50i-a64-pinephone-1.2b.dts new file mode 100644 index 00000000000..cbcfa2b0ac6 --- /dev/null +++ b/arch/arm/dts/sun50i-a64-pinephone-1.2b.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (C) 2020 Ondrej Jirman + +/dts-v1/; + +#include "sun50i-a64-pinephone-1.2.dts" + +/ { + model = "Pine64 PinePhone (1.2b)"; + compatible = "pine64,pinephone-1.2b", "pine64,pinephone", "allwinner,sun50i-a64"; +}; + +&lis3mdl { + status = "disabled"; +}; + diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 1305302060b..aa4f5394413 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,15 @@ DECLARE_GLOBAL_DATA_PTR; +#define PINEPHONE_LIS3MDL_I2C_ADDR 0x1E + +/* I2C1 */ +#if defined(CONFIG_I2C0_ENABLE) +#define PINEPHONE_LIS3MDL_I2C_BUS 1 +#else +#define PINEPHONE_LIS3MDL_I2C_BUS 0 +#endif + void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE @@ -602,7 +612,9 @@ void sunxi_board_init(void) #if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \ defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \ - defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER + defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER || \ + defined CONFIG_AXP803_POWER + power_failed = axp_init(); if (IS_ENABLED(CONFIG_AXP_DISABLE_BOOT_ON_POWERON) && !power_failed) { @@ -619,11 +631,12 @@ void sunxi_board_init(void) defined CONFIG_AXP818_POWER power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT); #endif -#if !defined(CONFIG_AXP305_POWER) +#if !defined(CONFIG_AXP305_POWER) && !defined(CONFIG_AXP803_POWER) 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_AXP803_POWER)) power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT); #endif #if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \ @@ -635,10 +648,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_AXP803_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_AXP803_POWER)) power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT); #endif #ifdef CONFIG_AXP209_POWER @@ -646,17 +660,19 @@ void sunxi_board_init(void) #endif #if defined(CONFIG_AXP221_POWER) || defined(CONFIG_AXP809_POWER) || \ - defined(CONFIG_AXP818_POWER) + defined(CONFIG_AXP818_POWER) || defined(CONFIG_AXP803_POWER) power_failed |= axp_set_dldo(1, CONFIG_AXP_DLDO1_VOLT); power_failed |= axp_set_dldo(2, CONFIG_AXP_DLDO2_VOLT); -#if !defined CONFIG_AXP809_POWER +#if !defined CONFIG_AXP809_POWER && !(defined(CONFIG_AXP803_POWER)) power_failed |= axp_set_dldo(3, CONFIG_AXP_DLDO3_VOLT); power_failed |= axp_set_dldo(4, CONFIG_AXP_DLDO4_VOLT); #endif +#if !(defined(CONFIG_AXP803_POWER)) power_failed |= axp_set_eldo(1, CONFIG_AXP_ELDO1_VOLT); power_failed |= axp_set_eldo(2, CONFIG_AXP_ELDO2_VOLT); power_failed |= axp_set_eldo(3, CONFIG_AXP_ELDO3_VOLT); #endif +#endif #ifdef CONFIG_AXP818_POWER power_failed |= axp_set_fldo(1, CONFIG_AXP_FLDO1_VOLT); @@ -962,6 +978,9 @@ int board_fit_config_name_match(const char *name) { const char *best_dt_name = get_spl_dt_name(); int ret; +#if CONFIG_IS_ENABLED(DM_I2C) + struct udevice *bus, *dev; +#endif #ifdef CONFIG_DEFAULT_DEVICE_TREE if (best_dt_name == NULL) @@ -988,11 +1007,21 @@ int board_fit_config_name_match(const char *name) udelay(100); /* PL6 is pulled low by the modem on v1.2. */ - if (gpio_get_value(SUNXI_GPL(6)) == 0) - best_dt_name = "sun50i-a64-pinephone-1.2"; - else - best_dt_name = "sun50i-a64-pinephone-1.1"; + if (gpio_get_value(SUNXI_GPL(6)) == 0) { + best_dt_name = "sun50i-a64-pinephone-1.2b"; + /* 1.2 has different I2C magnetometer */ +#if CONFIG_IS_ENABLED(DM_I2C) + if (!uclass_get_device_by_seq(UCLASS_I2C, PINEPHONE_LIS3MDL_I2C_BUS, &bus)) + if (!dm_i2c_probe(bus, PINEPHONE_LIS3MDL_I2C_ADDR, 0, &dev)) + best_dt_name = "sun50i-a64-pinephone-1.2"; +#else + if (!i2c_set_bus_num(PINEPHONE_LIS3MDL_I2C_BUS)) + if (!i2c_probe(PINEPHONE_LIS3MDL_I2C_ADDR)) + best_dt_name = "sun50i-a64-pinephone-1.2"; +#endif + } else + best_dt_name = "sun50i-a64-pinephone-1.1"; sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_DISABLE); sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_DISABLE); prcm_apb0_disable(PRCM_APB0_GATE_PIO); diff --git a/configs/pinephone_defconfig b/configs/pinephone_defconfig index eebc6769015..7400ddb35d2 100644 --- a/configs/pinephone_defconfig +++ b/configs/pinephone_defconfig @@ -9,11 +9,19 @@ CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y CONFIG_DRAM_CLK=552 CONFIG_DRAM_ZQ=3881949 CONFIG_MMC_SUNXI_SLOT_EXTRA=2 +CONFIG_I2C1_ENABLE=y CONFIG_PINEPHONE_DT_SELECTION=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set -CONFIG_OF_LIST="sun50i-a64-pinephone-1.1 sun50i-a64-pinephone-1.2" +CONFIG_SPL_I2C=y +CONFIG_OF_LIST="sun50i-a64-pinephone-1.1 sun50i-a64-pinephone-1.2 sun50i-a64-pinephone-1.2b" +CONFIG_SPL_SYS_I2C_LEGACY=y +CONFIG_SYS_I2C_SUN8I_RSB=y +CONFIG_SYS_I2C_MVTWSI=y CONFIG_LED_STATUS=y CONFIG_LED_STATUS_GPIO=y CONFIG_LED_STATUS0=y CONFIG_LED_STATUS_BIT=114 CONFIG_LED_STATUS_STATE=2 +CONFIG_AXP803_POWER=y +CONFIG_AXP_DLDO1_VOLT=3300 +CONFIG_AXP_DLDO2_VOLT=4200 diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 7f3b990d231..158009ca815 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 AXP803_POWER + bool "axp803 pmic support" + depends on MACH_SUN50I + select AXP_PMIC_BUS + select CMD_POWEROFF + ---help--- + Say y here to enable support for the axp803 pmic found on A64 boards. + config AXP809_POWER bool "axp809 pmic support" depends on MACH_SUN9I @@ -307,7 +315,7 @@ config AXP_ALDO4_VOLT config AXP_DLDO1_VOLT int "axp pmic dldo1 voltage" - depends on AXP221_POWER || AXP809_POWER || AXP818_POWER + depends on AXP221_POWER || AXP803_POWER|| AXP809_POWER || AXP818_POWER default 0 ---help--- Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to @@ -317,7 +325,7 @@ config AXP_DLDO1_VOLT config AXP_DLDO2_VOLT int "axp pmic dldo2 voltage" - depends on AXP221_POWER || AXP809_POWER || AXP818_POWER + depends on AXP221_POWER || AXP803_POWER|| AXP809_POWER || AXP818_POWER default 3000 if MACH_SUN9I default 0 ---help--- diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ba64b2c5938..c4c84feecac 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_AXP803_POWER) += axp803.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/axp803.c b/drivers/power/axp803.c new file mode 100644 index 00000000000..f5016d296d9 --- /dev/null +++ b/drivers/power/axp803.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AXP809 driver based on AXP221 driver + * + * + * (C) Copyright 2016 Chen-Yu Tsai + * + * Based on axp221.c + * (C) Copyright 2014 Hans de Goede + * (C) Copyright 2013 Oliver Schinagl + */ + +#include +#include +#include +#include +#include + + +static u8 axp803_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 = axp803_mvolt_to_cfg(mvolt, 1600, 3400, 100); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC1_EN); + + ret = pmic_bus_write(AXP803_DCDC1_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC1_EN); +} + +int axp_set_dcdc2(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 70 + axp803_mvolt_to_cfg(mvolt, 1220, 1300, 20); + else + cfg = axp803_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC2_EN); + + ret = pmic_bus_write(AXP803_DCDC2_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC2_EN); +} + +int axp_set_dcdc3(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 70 + axp803_mvolt_to_cfg(mvolt, 1220, 1300, 20); + else + cfg = axp803_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC3_EN); + + ret = pmic_bus_write(AXP803_DCDC3_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC3_EN); +} + +int axp_set_dcdc5(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1140) + cfg = 32 + axp803_mvolt_to_cfg(mvolt, 1140, 1840, 20); + else + cfg = axp803_mvolt_to_cfg(mvolt, 800, 1120, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC5_EN); + + ret = pmic_bus_write(AXP803_DCDC5_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL1, + AXP803_OUTPUT_CTRL1_DCDC5_EN); +} + +int axp_set_aldo(int aldo_num, unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (aldo_num < 1 || aldo_num > 3) + return -EINVAL; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL3, + AXP803_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1)); + + cfg = axp803_mvolt_to_cfg(mvolt, 700, 3300, 100); + ret = pmic_bus_write(AXP803_ALDO1_CTRL + (aldo_num - 1), cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL3, + AXP803_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1)); +} + +int axp_set_aldo1(unsigned int mvolt) +{ + return axp_set_aldo(1, mvolt); +} + +int axp_set_aldo2(unsigned int mvolt) +{ + return axp_set_aldo(2, mvolt); +} + +int axp_set_aldo3(unsigned int mvolt) +{ + return axp_set_aldo(3, mvolt); +} + +int axp_set_dldo(int dldo_num, unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (dldo_num < 1 || dldo_num > 4) + return -EINVAL; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1)); + + cfg = axp803_mvolt_to_cfg(mvolt, 700, 3300, 100); + if (dldo_num == 2 && mvolt > 3300) + cfg += 1 + axp803_mvolt_to_cfg(mvolt, 3400, 4200, 200); + ret = pmic_bus_write(AXP803_DLDO1_CTRL + (dldo_num - 1), cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1)); +} + +int axp_set_eldo(int eldo_num, unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (eldo_num < 1 || eldo_num > 3) + return -EINVAL; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1)); + + cfg = axp803_mvolt_to_cfg(mvolt, 700, 1900, 50); + ret = pmic_bus_write(AXP803_ELDO1_CTRL + (eldo_num - 1), cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1)); +} + +int axp_set_fldo(int fldo_num, unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (fldo_num < 1 || fldo_num > 2) + return -EINVAL; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL3, + AXP803_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1)); + + cfg = axp803_mvolt_to_cfg(mvolt, 700, 1450, 50); + ret = pmic_bus_write(AXP803_FLDO1_CTRL + (fldo_num - 1), cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP803_OUTPUT_CTRL3, + AXP803_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1)); +} + +int axp_set_sw(bool on) +{ + if (on) + return pmic_bus_setbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_SW_EN); + + return pmic_bus_clrbits(AXP803_OUTPUT_CTRL2, + AXP803_OUTPUT_CTRL2_SW_EN); +} + +int axp_init(void) +{ + return pmic_bus_init(); +} + +#if !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF) +int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + pmic_bus_write(AXP803_SHUTDOWN, AXP803_SHUTDOWN_POWEROFF); + + /* infinite loop during shutdown */ + while (1) {} + + /* not reached */ + return 0; +} +#endif diff --git a/include/axp803.h b/include/axp803.h new file mode 100644 index 00000000000..b382f3a5ecd --- /dev/null +++ b/include/axp803.h @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2016 Icenowy Zheng + * + * Based on axp818.h, which is: + * (C) Copyright 2015 Vishnu Patekar + * + * X-Powers AXP803 Power Management IC driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#define AXP803_CHIP_ID 0x03 + +#define AXP803_OUTPUT_CTRL1 0x10 +#define AXP803_OUTPUT_CTRL1_DCDC1_EN (1 << 0) +#define AXP803_OUTPUT_CTRL1_DCDC2_EN (1 << 1) +#define AXP803_OUTPUT_CTRL1_DCDC3_EN (1 << 2) +#define AXP803_OUTPUT_CTRL1_DCDC4_EN (1 << 3) +#define AXP803_OUTPUT_CTRL1_DCDC5_EN (1 << 4) +#define AXP803_OUTPUT_CTRL1_DCDC6_EN (1 << 5) +#define AXP803_OUTPUT_CTRL2 0x12 +#define AXP803_OUTPUT_CTRL2_ELDO1_EN (1 << 0) +#define AXP803_OUTPUT_CTRL2_ELDO2_EN (1 << 1) +#define AXP803_OUTPUT_CTRL2_ELDO3_EN (1 << 2) +#define AXP803_OUTPUT_CTRL2_DLDO1_EN (1 << 3) +#define AXP803_OUTPUT_CTRL2_DLDO2_EN (1 << 4) +#define AXP803_OUTPUT_CTRL2_DLDO3_EN (1 << 5) +#define AXP803_OUTPUT_CTRL2_DLDO4_EN (1 << 6) +#define AXP803_OUTPUT_CTRL2_SW_EN (1 << 7) +#define AXP803_OUTPUT_CTRL3 0x13 +#define AXP803_OUTPUT_CTRL3_FLDO1_EN (1 << 2) +#define AXP803_OUTPUT_CTRL3_FLDO2_EN (1 << 3) +#define AXP803_OUTPUT_CTRL3_ALDO1_EN (1 << 5) +#define AXP803_OUTPUT_CTRL3_ALDO2_EN (1 << 6) +#define AXP803_OUTPUT_CTRL3_ALDO3_EN (1 << 7) + +#define AXP803_DLDO1_CTRL 0x15 +#define AXP803_DLDO2_CTRL 0x16 +#define AXP803_DLDO3_CTRL 0x17 +#define AXP803_DLDO4_CTRL 0x18 +#define AXP803_ELDO1_CTRL 0x19 +#define AXP803_ELDO2_CTRL 0x1a +#define AXP803_ELDO3_CTRL 0x1b +#define AXP803_FLDO1_CTRL 0x1c +#define AXP803_FLDO2_CTRL 0x1d +#define AXP803_DCDC1_CTRL 0x20 +#define AXP803_DCDC2_CTRL 0x21 +#define AXP803_DCDC3_CTRL 0x22 +#define AXP803_DCDC4_CTRL 0x23 +#define AXP803_DCDC5_CTRL 0x24 +#define AXP803_DCDC6_CTRL 0x25 + +#define AXP803_ALDO1_CTRL 0x28 +#define AXP803_ALDO2_CTRL 0x29 +#define AXP803_ALDO3_CTRL 0x2a + +#define AXP803_SHUTDOWN 0x32 +#define AXP803_SHUTDOWN_POWEROFF (1 << 7) + +/* For axp_gpio.c */ +#define AXP_POWER_STATUS 0x00 +#define AXP_POWER_STATUS_VBUS_PRESENT (1 << 5) +#define AXP_VBUS_IPSOUT 0x30 +#define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2) +#define AXP_MISC_CTRL 0x8f +#define AXP_MISC_CTRL_N_VBUSEN_FUNC (1 << 4) +#define AXP_GPIO0_CTRL 0x90 +#define AXP_GPIO1_CTRL 0x92 +#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */ +#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */ +#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */ +#define AXP_GPIO_STATE 0x94 +#define AXP_GPIO_STATE_OFFSET 0 diff --git a/include/axp_pmic.h b/include/axp_pmic.h index 4ac64865831..af1d3f0368b 100644 --- a/include/axp_pmic.h +++ b/include/axp_pmic.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #define AXP_PMIC_MODE_REG 0x3e