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