xref: /rk3399_ARM-atf/plat/allwinner/sun50i_h6/sunxi_power.c (revision 6d37282807c8540319777cb50f411a2e56607438)
17c26b6ecSIcenowy Zheng /*
27c26b6ecSIcenowy Zheng  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
37c26b6ecSIcenowy Zheng  * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
47c26b6ecSIcenowy Zheng  *
57c26b6ecSIcenowy Zheng  * SPDX-License-Identifier: BSD-3-Clause
67c26b6ecSIcenowy Zheng  */
77c26b6ecSIcenowy Zheng 
87c26b6ecSIcenowy Zheng #include <debug.h>
9*6d372828SIcenowy Zheng #include <delay_timer.h>
10*6d372828SIcenowy Zheng #include <errno.h>
11*6d372828SIcenowy Zheng #include <mmio.h>
12*6d372828SIcenowy Zheng #include <mentor/mi2cv.h>
13*6d372828SIcenowy Zheng #include <string.h>
14*6d372828SIcenowy Zheng #include <sunxi_mmap.h>
15*6d372828SIcenowy Zheng 
16*6d372828SIcenowy Zheng #define AXP805_ADDR	0x36
17*6d372828SIcenowy Zheng #define AXP805_ID	0x03
18*6d372828SIcenowy Zheng 
19*6d372828SIcenowy Zheng enum pmic_type {
20*6d372828SIcenowy Zheng 	NO_PMIC,
21*6d372828SIcenowy Zheng 	AXP805,
22*6d372828SIcenowy Zheng };
23*6d372828SIcenowy Zheng 
24*6d372828SIcenowy Zheng enum pmic_type pmic;
25*6d372828SIcenowy Zheng 
26*6d372828SIcenowy Zheng static int sunxi_init_r_i2c(void)
27*6d372828SIcenowy Zheng {
28*6d372828SIcenowy Zheng 	uint32_t reg;
29*6d372828SIcenowy Zheng 
30*6d372828SIcenowy Zheng 	/* get currently configured function for pins PL0 and PL1 */
31*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
32*6d372828SIcenowy Zheng 	if ((reg & 0xff) == 0x33) {
33*6d372828SIcenowy Zheng 		NOTICE("PMIC: already configured for TWI\n");
34*6d372828SIcenowy Zheng 	}
35*6d372828SIcenowy Zheng 
36*6d372828SIcenowy Zheng 	/* switch pins PL0 and PL1 to I2C */
37*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
38*6d372828SIcenowy Zheng 
39*6d372828SIcenowy Zheng 	/* level 2 drive strength */
40*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
41*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
42*6d372828SIcenowy Zheng 
43*6d372828SIcenowy Zheng 	/* set both ports to pull-up */
44*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
45*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
46*6d372828SIcenowy Zheng 
47*6d372828SIcenowy Zheng 	/* assert & de-assert reset of R_I2C */
48*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
49*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
50*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
51*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
52*6d372828SIcenowy Zheng 
53*6d372828SIcenowy Zheng 	/* un-gate R_I2C clock */
54*6d372828SIcenowy Zheng 	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
55*6d372828SIcenowy Zheng 	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
56*6d372828SIcenowy Zheng 
57*6d372828SIcenowy Zheng 	/* call mi2cv driver */
58*6d372828SIcenowy Zheng 	i2c_init((void *)SUNXI_R_I2C_BASE);
59*6d372828SIcenowy Zheng 
60*6d372828SIcenowy Zheng 	return 0;
61*6d372828SIcenowy Zheng }
62*6d372828SIcenowy Zheng 
63*6d372828SIcenowy Zheng int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
64*6d372828SIcenowy Zheng {
65*6d372828SIcenowy Zheng 	int ret;
66*6d372828SIcenowy Zheng 
67*6d372828SIcenowy Zheng 	ret = i2c_write(chip, 0, 0, &reg, 1);
68*6d372828SIcenowy Zheng 	if (ret)
69*6d372828SIcenowy Zheng 		return ret;
70*6d372828SIcenowy Zheng 
71*6d372828SIcenowy Zheng 	return i2c_read(chip, 0, 0, val, 1);
72*6d372828SIcenowy Zheng }
73*6d372828SIcenowy Zheng 
74*6d372828SIcenowy Zheng int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
75*6d372828SIcenowy Zheng {
76*6d372828SIcenowy Zheng 	return i2c_write(chip, reg, 1, &val, 1);
77*6d372828SIcenowy Zheng }
78*6d372828SIcenowy Zheng 
79*6d372828SIcenowy Zheng static int axp805_probe(void)
80*6d372828SIcenowy Zheng {
81*6d372828SIcenowy Zheng 	int ret;
82*6d372828SIcenowy Zheng 	uint8_t val;
83*6d372828SIcenowy Zheng 
84*6d372828SIcenowy Zheng 	ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
85*6d372828SIcenowy Zheng 	if (ret) {
86*6d372828SIcenowy Zheng 		ERROR("PMIC: Cannot put AXP805 to master mode.\n");
87*6d372828SIcenowy Zheng 		return -EPERM;
88*6d372828SIcenowy Zheng 	}
89*6d372828SIcenowy Zheng 
90*6d372828SIcenowy Zheng 	ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
91*6d372828SIcenowy Zheng 
92*6d372828SIcenowy Zheng 	if (!ret && ((val & 0xcf) == 0x40))
93*6d372828SIcenowy Zheng 		NOTICE("PMIC: AXP805 detected\n");
94*6d372828SIcenowy Zheng 	else if (ret) {
95*6d372828SIcenowy Zheng 		ERROR("PMIC: Cannot communicate with AXP805.\n");
96*6d372828SIcenowy Zheng 		return -EPERM;
97*6d372828SIcenowy Zheng 	} else {
98*6d372828SIcenowy Zheng 		ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
99*6d372828SIcenowy Zheng 		return -EINVAL;
100*6d372828SIcenowy Zheng 	}
101*6d372828SIcenowy Zheng 
102*6d372828SIcenowy Zheng 	return 0;
103*6d372828SIcenowy Zheng }
1047c26b6ecSIcenowy Zheng 
1057c26b6ecSIcenowy Zheng int sunxi_pmic_setup(void)
1067c26b6ecSIcenowy Zheng {
107*6d372828SIcenowy Zheng 	int ret;
108*6d372828SIcenowy Zheng 
109*6d372828SIcenowy Zheng 	sunxi_init_r_i2c();
110*6d372828SIcenowy Zheng 
111*6d372828SIcenowy Zheng 	NOTICE("PMIC: Probing AXP805\n");
112*6d372828SIcenowy Zheng 	pmic = AXP805;
113*6d372828SIcenowy Zheng 
114*6d372828SIcenowy Zheng 	ret = axp805_probe();
115*6d372828SIcenowy Zheng 	if (ret)
116*6d372828SIcenowy Zheng 		pmic = NO_PMIC;
117*6d372828SIcenowy Zheng 	else
118*6d372828SIcenowy Zheng 		pmic = AXP805;
1197c26b6ecSIcenowy Zheng 
1207c26b6ecSIcenowy Zheng 	return 0;
1217c26b6ecSIcenowy Zheng }
122