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