blob: f109ccece304a28a5aa2b61e09034b09ffd8da23 [file] [log] [blame]
Icenowy Zheng7508bef2018-07-21 20:41:12 +08001/*
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
Icenowy Zhengbd57eb52018-07-22 21:52:50 +08008#include <arch_helpers.h>
Icenowy Zheng7508bef2018-07-21 20:41:12 +08009#include <debug.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +080010#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
20enum pmic_type {
21 NO_PMIC,
22 AXP805,
23};
24
25enum pmic_type pmic;
26
27static int sunxi_init_r_i2c(void)
28{
29 uint32_t reg;
30
31 /* get currently configured function for pins PL0 and PL1 */
32 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
33 if ((reg & 0xff) == 0x33) {
34 NOTICE("PMIC: already configured for TWI\n");
35 }
36
37 /* switch pins PL0 and PL1 to I2C */
38 mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
39
40 /* level 2 drive strength */
41 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
42 mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
43
44 /* set both ports to pull-up */
45 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
46 mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
47
48 /* assert & de-assert reset of R_I2C */
49 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
50 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
51 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
52 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
53
54 /* un-gate R_I2C clock */
55 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
56 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
57
58 /* call mi2cv driver */
59 i2c_init((void *)SUNXI_R_I2C_BASE);
60
61 return 0;
62}
63
64int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
65{
66 int ret;
67
68 ret = i2c_write(chip, 0, 0, &reg, 1);
69 if (ret)
70 return ret;
71
72 return i2c_read(chip, 0, 0, val, 1);
73}
74
75int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
76{
77 return i2c_write(chip, reg, 1, &val, 1);
78}
79
80static int axp805_probe(void)
81{
82 int ret;
83 uint8_t val;
84
85 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
86 if (ret) {
87 ERROR("PMIC: Cannot put AXP805 to master mode.\n");
88 return -EPERM;
89 }
90
91 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
92
93 if (!ret && ((val & 0xcf) == 0x40))
94 NOTICE("PMIC: AXP805 detected\n");
95 else if (ret) {
96 ERROR("PMIC: Cannot communicate with AXP805.\n");
97 return -EPERM;
98 } else {
99 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
100 return -EINVAL;
101 }
102
103 return 0;
104}
Icenowy Zheng7508bef2018-07-21 20:41:12 +0800105
106int sunxi_pmic_setup(void)
107{
Icenowy Zheng8d769822018-07-22 21:30:14 +0800108 int ret;
109
110 sunxi_init_r_i2c();
111
112 NOTICE("PMIC: Probing AXP805\n");
113 pmic = AXP805;
114
115 ret = axp805_probe();
116 if (ret)
117 pmic = NO_PMIC;
118 else
119 pmic = AXP805;
Icenowy Zheng7508bef2018-07-21 20:41:12 +0800120
121 return 0;
122}
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800123
124void __dead2 sunxi_power_down(void)
125{
126 uint8_t val;
127
128 switch (pmic) {
129 case AXP805:
130 val = 0x26; /* Default value for REG 32H */
131 axp_i2c_read(AXP805_ADDR, 0x32, &val);
132 val |= 0x80;
133 axp_i2c_write(AXP805_ADDR, 0x32, val);
134 break;
135 default:
136 break;
137 }
138
139 udelay(1000);
140 ERROR("PSCI: Cannot communicate with PMIC, halting\n");
141 wfi();
142 panic();
143}