blob: bbc9e911115f1ab906650a0db239964e5a1367f5 [file] [log] [blame]
Andre Przywarad17d0512023-07-30 01:11:01 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * AXP313(a) driver
4 *
5 * (C) Copyright 2023 Arm Ltd.
6 *
7 * Based on axp305.c
8 * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
9 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
10 * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
11 */
12
13#include <common.h>
14#include <command.h>
15#include <errno.h>
16#include <asm/arch/pmic_bus.h>
17#include <axp_pmic.h>
18
19enum axp313_reg {
20 AXP313_CHIP_VERSION = 0x03,
21 AXP313_OUTPUT_CTRL = 0x10,
22 AXP313_DCDC1_CTRL = 0x13,
23 AXP313_SHUTDOWN = 0x1a,
24};
25
26#define AXP313_CHIP_VERSION_MASK 0xcf
27#define AXP313_CHIP_VERSION_AXP1530 0x48
28#define AXP313_CHIP_VERSION_AXP313A 0x4b
29#define AXP313_CHIP_VERSION_AXP313B 0x4c
30
31#define AXP313_DCDC_SPLIT_OFFSET 71
32#define AXP313_DCDC_SPLIT_MVOLT 1200
33
34#define AXP313_POWEROFF BIT(7)
35
36static u8 mvolt_to_cfg(int mvolt, int min, int max, int div)
37{
38 if (mvolt < min)
39 mvolt = min;
40 else if (mvolt > max)
41 mvolt = max;
42
43 return (mvolt - min) / div;
44}
45
46static int axp_set_dcdc(int dcdc_num, unsigned int mvolt)
47{
48 int ret;
49 u8 cfg, enable_mask = 1U << (dcdc_num - 1);
50 int volt_reg = AXP313_DCDC1_CTRL + dcdc_num - 1;
51 int max_mV;
52
53 switch (dcdc_num) {
54 case 1:
55 case 2:
56 max_mV = 1540;
57 break;
58 case 3:
59 /*
60 * The manual defines a different split point, but tests
61 * show that it's the same 1200mV as for DCDC1/2.
62 */
63 max_mV = 1840;
64 break;
65 default:
66 return -EINVAL;
67 }
68
69 if (mvolt > AXP313_DCDC_SPLIT_MVOLT)
70 cfg = AXP313_DCDC_SPLIT_OFFSET + mvolt_to_cfg(mvolt,
71 AXP313_DCDC_SPLIT_MVOLT + 20, max_mV, 20);
72 else
73 cfg = mvolt_to_cfg(mvolt, 500, AXP313_DCDC_SPLIT_MVOLT, 10);
74
75 if (mvolt == 0)
76 return pmic_bus_clrbits(AXP313_OUTPUT_CTRL, enable_mask);
77
78 debug("DCDC%d: writing 0x%x to reg 0x%x\n", dcdc_num, cfg, volt_reg);
79 ret = pmic_bus_write(volt_reg, cfg);
80 if (ret)
81 return ret;
82
83 return pmic_bus_setbits(AXP313_OUTPUT_CTRL, enable_mask);
84}
85
86int axp_set_dcdc2(unsigned int mvolt)
87{
88 return axp_set_dcdc(2, mvolt);
89}
90
91int axp_set_dcdc3(unsigned int mvolt)
92{
93 return axp_set_dcdc(3, mvolt);
94}
95
96int axp_init(void)
97{
98 u8 axp_chip_id;
99 int ret;
100
101 ret = pmic_bus_init();
102 if (ret)
103 return ret;
104
105 ret = pmic_bus_read(AXP313_CHIP_VERSION, &axp_chip_id);
106 if (ret)
107 return ret;
108
109 axp_chip_id &= AXP313_CHIP_VERSION_MASK;
110 switch (axp_chip_id) {
111 case AXP313_CHIP_VERSION_AXP1530:
112 case AXP313_CHIP_VERSION_AXP313A:
113 case AXP313_CHIP_VERSION_AXP313B:
114 break;
115 default:
116 debug("unknown PMIC: 0x%x\n", axp_chip_id);
117 return -EINVAL;
118 }
119
120 return ret;
121}
122
123#if !CONFIG_IS_ENABLED(ARM_PSCI_FW) && !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
124int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
125{
126 pmic_bus_write(AXP313_SHUTDOWN, AXP313_POWEROFF);
127
128 /* infinite loop during shutdown */
129 while (1) {}
130
131 /* not reached */
132 return 0;
133}
134#endif