blob: 7bdac8ab0b6acd49029933dd51b9f5963811721a [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>
Andre Przywara67537762018-10-14 22:13:53 +010015#include <sunxi_def.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +080016#include <sunxi_mmap.h>
Andre Przywara456208a2018-10-14 12:02:02 +010017#include <sunxi_private.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +080018
19#define AXP805_ADDR 0x36
20#define AXP805_ID 0x03
21
22enum pmic_type {
23 NO_PMIC,
24 AXP805,
25};
26
27enum pmic_type pmic;
28
Icenowy Zheng8d769822018-07-22 21:30:14 +080029int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
30{
31 int ret;
32
33 ret = i2c_write(chip, 0, 0, &reg, 1);
34 if (ret)
35 return ret;
36
37 return i2c_read(chip, 0, 0, val, 1);
38}
39
40int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
41{
42 return i2c_write(chip, reg, 1, &val, 1);
43}
44
45static int axp805_probe(void)
46{
47 int ret;
48 uint8_t val;
49
50 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
51 if (ret) {
52 ERROR("PMIC: Cannot put AXP805 to master mode.\n");
53 return -EPERM;
54 }
55
56 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
57
58 if (!ret && ((val & 0xcf) == 0x40))
59 NOTICE("PMIC: AXP805 detected\n");
60 else if (ret) {
61 ERROR("PMIC: Cannot communicate with AXP805.\n");
62 return -EPERM;
63 } else {
64 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
65 return -EINVAL;
66 }
67
68 return 0;
69}
Icenowy Zheng7508bef2018-07-21 20:41:12 +080070
Andre Przywara4e4b1e62018-09-08 19:18:37 +010071int sunxi_pmic_setup(uint16_t socid, const void *fdt)
Icenowy Zheng7508bef2018-07-21 20:41:12 +080072{
Icenowy Zheng8d769822018-07-22 21:30:14 +080073 int ret;
74
Andre Przywara67537762018-10-14 22:13:53 +010075 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
76 /* initialise mi2cv driver */
77 i2c_init((void *)SUNXI_R_I2C_BASE);
Icenowy Zheng8d769822018-07-22 21:30:14 +080078
79 NOTICE("PMIC: Probing AXP805\n");
80 pmic = AXP805;
81
82 ret = axp805_probe();
83 if (ret)
84 pmic = NO_PMIC;
85 else
86 pmic = AXP805;
Icenowy Zheng7508bef2018-07-21 20:41:12 +080087
88 return 0;
89}
Icenowy Zhengbd57eb52018-07-22 21:52:50 +080090
91void __dead2 sunxi_power_down(void)
92{
93 uint8_t val;
94
95 switch (pmic) {
96 case AXP805:
Andre Przywara67537762018-10-14 22:13:53 +010097 /* Re-initialise after rich OS might have used it. */
98 sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
99 /* initialise mi2cv driver */
100 i2c_init((void *)SUNXI_R_I2C_BASE);
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800101 axp_i2c_read(AXP805_ADDR, 0x32, &val);
Andre Przywaraaffb9322018-09-09 00:38:58 +0100102 axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
Icenowy Zhengbd57eb52018-07-22 21:52:50 +0800103 break;
104 default:
105 break;
106 }
107
108 udelay(1000);
109 ERROR("PSCI: Cannot communicate with PMIC, halting\n");
110 wfi();
111 panic();
112}