blob: 3638a199c35bb23b5b792b22bbfbe87a19767191 [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
8#include <debug.h>
Icenowy Zheng8d769822018-07-22 21:30:14 +08009#include <delay_timer.h>
10#include <errno.h>
11#include <mmio.h>
12#include <mentor/mi2cv.h>
13#include <string.h>
14#include <sunxi_mmap.h>
15
16#define AXP805_ADDR 0x36
17#define AXP805_ID 0x03
18
19enum pmic_type {
20 NO_PMIC,
21 AXP805,
22};
23
24enum pmic_type pmic;
25
26static int sunxi_init_r_i2c(void)
27{
28 uint32_t reg;
29
30 /* get currently configured function for pins PL0 and PL1 */
31 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
32 if ((reg & 0xff) == 0x33) {
33 NOTICE("PMIC: already configured for TWI\n");
34 }
35
36 /* switch pins PL0 and PL1 to I2C */
37 mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
38
39 /* level 2 drive strength */
40 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
41 mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
42
43 /* set both ports to pull-up */
44 reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
45 mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
46
47 /* assert & de-assert reset of R_I2C */
48 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
49 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
50 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
51 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
52
53 /* un-gate R_I2C clock */
54 reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
55 mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
56
57 /* call mi2cv driver */
58 i2c_init((void *)SUNXI_R_I2C_BASE);
59
60 return 0;
61}
62
63int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
64{
65 int ret;
66
67 ret = i2c_write(chip, 0, 0, &reg, 1);
68 if (ret)
69 return ret;
70
71 return i2c_read(chip, 0, 0, val, 1);
72}
73
74int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
75{
76 return i2c_write(chip, reg, 1, &val, 1);
77}
78
79static int axp805_probe(void)
80{
81 int ret;
82 uint8_t val;
83
84 ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
85 if (ret) {
86 ERROR("PMIC: Cannot put AXP805 to master mode.\n");
87 return -EPERM;
88 }
89
90 ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
91
92 if (!ret && ((val & 0xcf) == 0x40))
93 NOTICE("PMIC: AXP805 detected\n");
94 else if (ret) {
95 ERROR("PMIC: Cannot communicate with AXP805.\n");
96 return -EPERM;
97 } else {
98 ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
99 return -EINVAL;
100 }
101
102 return 0;
103}
Icenowy Zheng7508bef2018-07-21 20:41:12 +0800104
105int sunxi_pmic_setup(void)
106{
Icenowy Zheng8d769822018-07-22 21:30:14 +0800107 int ret;
108
109 sunxi_init_r_i2c();
110
111 NOTICE("PMIC: Probing AXP805\n");
112 pmic = AXP805;
113
114 ret = axp805_probe();
115 if (ret)
116 pmic = NO_PMIC;
117 else
118 pmic = AXP805;
Icenowy Zheng7508bef2018-07-21 20:41:12 +0800119
120 return 0;
121}