1813c7372Svishnupatekar /*
2813c7372Svishnupatekar * AXP818 driver based on AXP221 driver
3813c7372Svishnupatekar *
4813c7372Svishnupatekar *
5813c7372Svishnupatekar * (C) Copyright 2015 Vishnu Patekar <vishnuptekar0510@gmail.com>
6813c7372Svishnupatekar *
7813c7372Svishnupatekar * Based on axp221.c
8813c7372Svishnupatekar * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
9813c7372Svishnupatekar * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
10813c7372Svishnupatekar *
11813c7372Svishnupatekar * SPDX-License-Identifier: GPL-2.0+
12813c7372Svishnupatekar */
13813c7372Svishnupatekar
14813c7372Svishnupatekar #include <common.h>
15813c7372Svishnupatekar #include <errno.h>
16813c7372Svishnupatekar #include <asm/arch/gpio.h>
17813c7372Svishnupatekar #include <asm/arch/pmic_bus.h>
18813c7372Svishnupatekar #include <axp_pmic.h>
19813c7372Svishnupatekar
axp818_mvolt_to_cfg(int mvolt,int min,int max,int div)20813c7372Svishnupatekar static u8 axp818_mvolt_to_cfg(int mvolt, int min, int max, int div)
21813c7372Svishnupatekar {
22813c7372Svishnupatekar if (mvolt < min)
23813c7372Svishnupatekar mvolt = min;
24813c7372Svishnupatekar else if (mvolt > max)
25813c7372Svishnupatekar mvolt = max;
26813c7372Svishnupatekar
27813c7372Svishnupatekar return (mvolt - min) / div;
28813c7372Svishnupatekar }
29813c7372Svishnupatekar
axp_set_dcdc1(unsigned int mvolt)30813c7372Svishnupatekar int axp_set_dcdc1(unsigned int mvolt)
31813c7372Svishnupatekar {
32813c7372Svishnupatekar int ret;
33813c7372Svishnupatekar u8 cfg = axp818_mvolt_to_cfg(mvolt, 1600, 3400, 100);
34813c7372Svishnupatekar
35813c7372Svishnupatekar if (mvolt == 0)
36813c7372Svishnupatekar return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
37813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC1_EN);
38813c7372Svishnupatekar
39813c7372Svishnupatekar ret = pmic_bus_write(AXP818_DCDC1_CTRL, cfg);
40813c7372Svishnupatekar if (ret)
41813c7372Svishnupatekar return ret;
42813c7372Svishnupatekar
43813c7372Svishnupatekar return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
44813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC1_EN);
45813c7372Svishnupatekar }
46813c7372Svishnupatekar
axp_set_dcdc2(unsigned int mvolt)47813c7372Svishnupatekar int axp_set_dcdc2(unsigned int mvolt)
48813c7372Svishnupatekar {
49813c7372Svishnupatekar int ret;
50813c7372Svishnupatekar u8 cfg;
51813c7372Svishnupatekar
52813c7372Svishnupatekar if (mvolt >= 1220)
53813c7372Svishnupatekar cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20);
54813c7372Svishnupatekar else
55813c7372Svishnupatekar cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10);
56813c7372Svishnupatekar
57813c7372Svishnupatekar if (mvolt == 0)
58813c7372Svishnupatekar return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
59813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC2_EN);
60813c7372Svishnupatekar
61813c7372Svishnupatekar ret = pmic_bus_write(AXP818_DCDC2_CTRL, cfg);
62813c7372Svishnupatekar if (ret)
63813c7372Svishnupatekar return ret;
64813c7372Svishnupatekar
65813c7372Svishnupatekar return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
66813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC2_EN);
67813c7372Svishnupatekar }
68813c7372Svishnupatekar
axp_set_dcdc3(unsigned int mvolt)69813c7372Svishnupatekar int axp_set_dcdc3(unsigned int mvolt)
70813c7372Svishnupatekar {
71813c7372Svishnupatekar int ret;
72813c7372Svishnupatekar u8 cfg;
73813c7372Svishnupatekar
74813c7372Svishnupatekar if (mvolt >= 1220)
75813c7372Svishnupatekar cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20);
76813c7372Svishnupatekar else
77813c7372Svishnupatekar cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10);
78813c7372Svishnupatekar
79813c7372Svishnupatekar if (mvolt == 0)
80813c7372Svishnupatekar return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
81813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC3_EN);
82813c7372Svishnupatekar
83813c7372Svishnupatekar ret = pmic_bus_write(AXP818_DCDC3_CTRL, cfg);
84813c7372Svishnupatekar if (ret)
85813c7372Svishnupatekar return ret;
86813c7372Svishnupatekar
87813c7372Svishnupatekar return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
88813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC3_EN);
89813c7372Svishnupatekar }
90813c7372Svishnupatekar
axp_set_dcdc5(unsigned int mvolt)91813c7372Svishnupatekar int axp_set_dcdc5(unsigned int mvolt)
92813c7372Svishnupatekar {
93813c7372Svishnupatekar int ret;
94813c7372Svishnupatekar u8 cfg;
95813c7372Svishnupatekar
96813c7372Svishnupatekar if (mvolt >= 1140)
97813c7372Svishnupatekar cfg = 32 + axp818_mvolt_to_cfg(mvolt, 1140, 1840, 20);
98813c7372Svishnupatekar else
99813c7372Svishnupatekar cfg = axp818_mvolt_to_cfg(mvolt, 800, 1120, 10);
100813c7372Svishnupatekar
101813c7372Svishnupatekar if (mvolt == 0)
102813c7372Svishnupatekar return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1,
103813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC5_EN);
104813c7372Svishnupatekar
105813c7372Svishnupatekar ret = pmic_bus_write(AXP818_DCDC5_CTRL, cfg);
106813c7372Svishnupatekar if (ret)
107813c7372Svishnupatekar return ret;
108813c7372Svishnupatekar
109813c7372Svishnupatekar return pmic_bus_setbits(AXP818_OUTPUT_CTRL1,
110813c7372Svishnupatekar AXP818_OUTPUT_CTRL1_DCDC5_EN);
111813c7372Svishnupatekar }
112813c7372Svishnupatekar
axp_set_aldo(int aldo_num,unsigned int mvolt)113f3c5045aSChen-Yu Tsai int axp_set_aldo(int aldo_num, unsigned int mvolt)
114f3c5045aSChen-Yu Tsai {
115f3c5045aSChen-Yu Tsai int ret;
116f3c5045aSChen-Yu Tsai u8 cfg;
117f3c5045aSChen-Yu Tsai
118f3c5045aSChen-Yu Tsai if (aldo_num < 1 || aldo_num > 3)
119f3c5045aSChen-Yu Tsai return -EINVAL;
120f3c5045aSChen-Yu Tsai
121f3c5045aSChen-Yu Tsai if (mvolt == 0)
122f3c5045aSChen-Yu Tsai return pmic_bus_clrbits(AXP818_OUTPUT_CTRL3,
123f3c5045aSChen-Yu Tsai AXP818_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
124f3c5045aSChen-Yu Tsai
125f3c5045aSChen-Yu Tsai cfg = axp818_mvolt_to_cfg(mvolt, 700, 3300, 100);
126f3c5045aSChen-Yu Tsai ret = pmic_bus_write(AXP818_ALDO1_CTRL + (aldo_num - 1), cfg);
127f3c5045aSChen-Yu Tsai if (ret)
128f3c5045aSChen-Yu Tsai return ret;
129f3c5045aSChen-Yu Tsai
130f3c5045aSChen-Yu Tsai return pmic_bus_setbits(AXP818_OUTPUT_CTRL3,
131f3c5045aSChen-Yu Tsai AXP818_OUTPUT_CTRL3_ALDO1_EN << (aldo_num - 1));
132f3c5045aSChen-Yu Tsai }
133f3c5045aSChen-Yu Tsai
134f3c5045aSChen-Yu Tsai /* TODO: re-work other AXP drivers to consolidate ALDO functions. */
axp_set_aldo1(unsigned int mvolt)135f3c5045aSChen-Yu Tsai int axp_set_aldo1(unsigned int mvolt)
136f3c5045aSChen-Yu Tsai {
137f3c5045aSChen-Yu Tsai return axp_set_aldo(1, mvolt);
138f3c5045aSChen-Yu Tsai }
139f3c5045aSChen-Yu Tsai
axp_set_aldo2(unsigned int mvolt)140f3c5045aSChen-Yu Tsai int axp_set_aldo2(unsigned int mvolt)
141f3c5045aSChen-Yu Tsai {
142f3c5045aSChen-Yu Tsai return axp_set_aldo(2, mvolt);
143f3c5045aSChen-Yu Tsai }
144f3c5045aSChen-Yu Tsai
axp_set_aldo3(unsigned int mvolt)145f3c5045aSChen-Yu Tsai int axp_set_aldo3(unsigned int mvolt)
146f3c5045aSChen-Yu Tsai {
147f3c5045aSChen-Yu Tsai return axp_set_aldo(3, mvolt);
148f3c5045aSChen-Yu Tsai }
149f3c5045aSChen-Yu Tsai
axp_set_dldo(int dldo_num,unsigned int mvolt)1500509efb7SChen-Yu Tsai int axp_set_dldo(int dldo_num, unsigned int mvolt)
1510509efb7SChen-Yu Tsai {
1520509efb7SChen-Yu Tsai int ret;
1530509efb7SChen-Yu Tsai u8 cfg;
1540509efb7SChen-Yu Tsai
1550509efb7SChen-Yu Tsai if (dldo_num < 1 || dldo_num > 4)
1560509efb7SChen-Yu Tsai return -EINVAL;
1570509efb7SChen-Yu Tsai
1580509efb7SChen-Yu Tsai if (mvolt == 0)
1590509efb7SChen-Yu Tsai return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
1600509efb7SChen-Yu Tsai AXP818_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1610509efb7SChen-Yu Tsai
1620509efb7SChen-Yu Tsai cfg = axp818_mvolt_to_cfg(mvolt, 700, 3300, 100);
1630509efb7SChen-Yu Tsai if (dldo_num == 2 && mvolt > 3300)
1640509efb7SChen-Yu Tsai cfg += 1 + axp818_mvolt_to_cfg(mvolt, 3400, 4200, 200);
1650509efb7SChen-Yu Tsai ret = pmic_bus_write(AXP818_ELDO1_CTRL + (dldo_num - 1), cfg);
1660509efb7SChen-Yu Tsai if (ret)
1670509efb7SChen-Yu Tsai return ret;
1680509efb7SChen-Yu Tsai
1690509efb7SChen-Yu Tsai return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
1700509efb7SChen-Yu Tsai AXP818_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1710509efb7SChen-Yu Tsai }
1720509efb7SChen-Yu Tsai
axp_set_eldo(int eldo_num,unsigned int mvolt)1730509efb7SChen-Yu Tsai int axp_set_eldo(int eldo_num, unsigned int mvolt)
1740509efb7SChen-Yu Tsai {
1750509efb7SChen-Yu Tsai int ret;
1760509efb7SChen-Yu Tsai u8 cfg;
1770509efb7SChen-Yu Tsai
1780509efb7SChen-Yu Tsai if (eldo_num < 1 || eldo_num > 3)
1790509efb7SChen-Yu Tsai return -EINVAL;
1800509efb7SChen-Yu Tsai
1810509efb7SChen-Yu Tsai if (mvolt == 0)
1820509efb7SChen-Yu Tsai return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
1830509efb7SChen-Yu Tsai AXP818_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
1840509efb7SChen-Yu Tsai
1850509efb7SChen-Yu Tsai cfg = axp818_mvolt_to_cfg(mvolt, 700, 1900, 50);
1860509efb7SChen-Yu Tsai ret = pmic_bus_write(AXP818_ELDO1_CTRL + (eldo_num - 1), cfg);
1870509efb7SChen-Yu Tsai if (ret)
1880509efb7SChen-Yu Tsai return ret;
1890509efb7SChen-Yu Tsai
1900509efb7SChen-Yu Tsai return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
1910509efb7SChen-Yu Tsai AXP818_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
1920509efb7SChen-Yu Tsai }
1930509efb7SChen-Yu Tsai
axp_set_fldo(int fldo_num,unsigned int mvolt)19438491d9cSChen-Yu Tsai int axp_set_fldo(int fldo_num, unsigned int mvolt)
19538491d9cSChen-Yu Tsai {
19638491d9cSChen-Yu Tsai int ret;
19738491d9cSChen-Yu Tsai u8 cfg;
19838491d9cSChen-Yu Tsai
19938491d9cSChen-Yu Tsai if (fldo_num < 1 || fldo_num > 3)
20038491d9cSChen-Yu Tsai return -EINVAL;
20138491d9cSChen-Yu Tsai
20238491d9cSChen-Yu Tsai if (mvolt == 0)
20338491d9cSChen-Yu Tsai return pmic_bus_clrbits(AXP818_OUTPUT_CTRL3,
20438491d9cSChen-Yu Tsai AXP818_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
20538491d9cSChen-Yu Tsai
20638491d9cSChen-Yu Tsai if (fldo_num < 3) {
20738491d9cSChen-Yu Tsai cfg = axp818_mvolt_to_cfg(mvolt, 700, 1450, 50);
20838491d9cSChen-Yu Tsai ret = pmic_bus_write(AXP818_FLDO1_CTRL + (fldo_num - 1), cfg);
20938491d9cSChen-Yu Tsai } else {
21038491d9cSChen-Yu Tsai /*
21138491d9cSChen-Yu Tsai * Special case for FLDO3, which is DCDC5 / 2 or FLDOIN / 2
21238491d9cSChen-Yu Tsai * Since FLDOIN is unknown, test against DCDC5.
21338491d9cSChen-Yu Tsai */
21438491d9cSChen-Yu Tsai if (mvolt * 2 == CONFIG_AXP_DCDC5_VOLT)
21538491d9cSChen-Yu Tsai ret = pmic_bus_clrbits(AXP818_FLDO2_3_CTRL,
21638491d9cSChen-Yu Tsai AXP818_FLDO2_3_CTRL_FLDO3_VOL);
21738491d9cSChen-Yu Tsai else
21838491d9cSChen-Yu Tsai ret = pmic_bus_setbits(AXP818_FLDO2_3_CTRL,
21938491d9cSChen-Yu Tsai AXP818_FLDO2_3_CTRL_FLDO3_VOL);
22038491d9cSChen-Yu Tsai }
22138491d9cSChen-Yu Tsai if (ret)
22238491d9cSChen-Yu Tsai return ret;
22338491d9cSChen-Yu Tsai
22438491d9cSChen-Yu Tsai return pmic_bus_setbits(AXP818_OUTPUT_CTRL3,
22538491d9cSChen-Yu Tsai AXP818_OUTPUT_CTRL3_FLDO1_EN << (fldo_num - 1));
22638491d9cSChen-Yu Tsai }
22738491d9cSChen-Yu Tsai
axp_set_sw(bool on)22815278ccbSChen-Yu Tsai int axp_set_sw(bool on)
22915278ccbSChen-Yu Tsai {
23015278ccbSChen-Yu Tsai if (on)
23115278ccbSChen-Yu Tsai return pmic_bus_setbits(AXP818_OUTPUT_CTRL2,
23215278ccbSChen-Yu Tsai AXP818_OUTPUT_CTRL2_SW_EN);
23315278ccbSChen-Yu Tsai
23415278ccbSChen-Yu Tsai return pmic_bus_clrbits(AXP818_OUTPUT_CTRL2,
23515278ccbSChen-Yu Tsai AXP818_OUTPUT_CTRL2_SW_EN);
23615278ccbSChen-Yu Tsai }
23715278ccbSChen-Yu Tsai
axp_init(void)238813c7372Svishnupatekar int axp_init(void)
239813c7372Svishnupatekar {
240813c7372Svishnupatekar u8 axp_chip_id;
241813c7372Svishnupatekar int ret;
242813c7372Svishnupatekar
243813c7372Svishnupatekar ret = pmic_bus_init();
244813c7372Svishnupatekar if (ret)
245813c7372Svishnupatekar return ret;
246813c7372Svishnupatekar
247813c7372Svishnupatekar ret = pmic_bus_read(AXP818_CHIP_ID, &axp_chip_id);
248813c7372Svishnupatekar if (ret)
249813c7372Svishnupatekar return ret;
250813c7372Svishnupatekar
251813c7372Svishnupatekar if (!(axp_chip_id == 0x51))
252813c7372Svishnupatekar return -ENODEV;
253813c7372Svishnupatekar else
254813c7372Svishnupatekar return ret;
255813c7372Svishnupatekar
256813c7372Svishnupatekar return 0;
257813c7372Svishnupatekar }
258*51199269SChen-Yu Tsai
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])259*51199269SChen-Yu Tsai int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
260*51199269SChen-Yu Tsai {
261*51199269SChen-Yu Tsai pmic_bus_write(AXP818_SHUTDOWN, AXP818_SHUTDOWN_POWEROFF);
262*51199269SChen-Yu Tsai
263*51199269SChen-Yu Tsai /* infinite loop during shutdown */
264*51199269SChen-Yu Tsai while (1) {}
265*51199269SChen-Yu Tsai
266*51199269SChen-Yu Tsai /* not reached */
267*51199269SChen-Yu Tsai return 0;
268*51199269SChen-Yu Tsai }
269