/* * AXP809 driver * * (C) Copyright 2016 Theobroma Systems Design und Consulting GmbH * Philipp Tomsich * * based on AXP221/AXP223 driver (axp221.c): * * (C) Copyright 2014 Hans de Goede * (C) Copyright 2013 Oliver Schinagl * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include static u8 axp809_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_dc5ldo(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 1400, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DC5LDO_EN); ret = pmic_bus_write(AXP809_DC5LDO_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DC5LDO_EN); } int axp_set_dcdc1(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 1600, 3400, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC1_EN); ret = pmic_bus_write(AXP809_DCDC1_CTRL, cfg); if (ret) return ret; ret = pmic_bus_setbits(AXP809_OUTPUT_CTRL2, AXP809_OUTPUT_CTRL2_DC1SW_EN); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC1_EN); } int axp_set_dcdc2(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC2_EN); ret = pmic_bus_write(AXP809_DCDC2_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC2_EN); } int axp_set_dcdc3(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1860, 20); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC3_EN); ret = pmic_bus_write(AXP809_DCDC3_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC3_EN); } int axp_set_dcdc4(unsigned int mvolt) { int ret; u8 cfg; /* DCDC4 has two separate ramps: 20mV steps for 600mV ... 1540mV 100mV steps for 1800mV ... 2600mV */ cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20); cfg += axp809_mvolt_to_cfg(mvolt, 1800, 2600, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC4_EN); ret = pmic_bus_write(AXP809_DCDC4_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC4_EN); } int axp_set_dcdc5(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 1000, 2550, 50); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC5_EN); ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC5_EN); } int axp_set_aldo1(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_ALDO1_EN); ret = pmic_bus_write(AXP809_ALDO1_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_ALDO1_EN); } int axp_set_aldo2(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_ALDO2_EN); ret = pmic_bus_write(AXP809_ALDO2_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_ALDO2_EN); } int axp_set_aldo3(unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100); if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2, AXP809_OUTPUT_CTRL2_ALDO3_EN); ret = pmic_bus_write(AXP809_ALDO3_CTRL, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL2, AXP809_OUTPUT_CTRL2_ALDO3_EN); } int axp_set_dldo(int dldo_num, unsigned int mvolt) { u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100); int ret; if (dldo_num < 1 || dldo_num > 2) return -EINVAL; if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2, AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1)); ret = pmic_bus_write(AXP809_DLDO1_CTRL + (dldo_num - 1), cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL2, AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1)); } int axp_set_eldo(int eldo_num, unsigned int mvolt) { int ret; u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100); u8 addr, bits; switch (eldo_num) { case 3: addr = AXP809_ELDO3_CTRL; bits = AXP809_OUTPUT_CTRL2_ELDO3_EN; break; case 2: addr = AXP809_ELDO2_CTRL; bits = AXP809_OUTPUT_CTRL2_ELDO2_EN; break; case 1: addr = AXP809_ELDO1_CTRL; bits = AXP809_OUTPUT_CTRL2_ELDO1_EN; break; default: return -EINVAL; } if (mvolt == 0) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2, bits); ret = pmic_bus_write(addr, cfg); if (ret) return ret; return pmic_bus_setbits(AXP809_OUTPUT_CTRL2, bits); } int axp_init(void) { u8 axp_chip_id; int ret; ret = pmic_bus_init(); if (ret) return ret; ret = pmic_bus_read(AXP809_VERSION, &axp_chip_id); if (ret) return ret; axp_chip_id &= AXP809_VERSION_CHIPID_MASK; if (!(axp_chip_id == AXP809_VERSION_CHIPID)) return -ENODEV; return 0; } int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { pmic_bus_write(AXP809_SHUTDOWN, AXP809_SHUTDOWN_POWEROFF); /* infinite loop during shutdown */ while (1) {} /* not reached */ return 0; }