]>
Commit | Line | Data |
---|---|---|
2c94611d SG |
1 | /* |
2 | * Copyright (c) 2013 The Chromium OS Authors. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <cros_ec.h> | |
9 | #include <errno.h> | |
10 | #include <power/tps65090_pmic.h> | |
11 | ||
12 | DECLARE_GLOBAL_DATA_PTR; | |
13 | ||
14 | #define TPS65090_ADDR 0x48 | |
15 | ||
16 | static struct tps65090 { | |
17 | struct cros_ec_dev *dev; /* The CROS_EC device */ | |
18 | } config; | |
19 | ||
20 | /* TPS65090 register addresses */ | |
21 | enum { | |
22 | REG_IRQ1 = 0, | |
23 | REG_CG_CTRL0 = 4, | |
24 | REG_CG_STATUS1 = 0xa, | |
25 | REG_FET1_CTRL = 0x0f, | |
26 | REG_FET2_CTRL, | |
27 | REG_FET3_CTRL, | |
28 | REG_FET4_CTRL, | |
29 | REG_FET5_CTRL, | |
30 | REG_FET6_CTRL, | |
31 | REG_FET7_CTRL, | |
32 | TPS65090_NUM_REGS, | |
33 | }; | |
34 | ||
35 | enum { | |
36 | IRQ1_VBATG = 1 << 3, | |
37 | CG_CTRL0_ENC_MASK = 0x01, | |
38 | ||
39 | MAX_FET_NUM = 7, | |
40 | MAX_CTRL_READ_TRIES = 5, | |
41 | ||
42 | /* TPS65090 FET_CTRL register values */ | |
43 | FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ | |
44 | FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ | |
45 | FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ | |
46 | FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ | |
47 | FET_CTRL_ENFET = 1 << 0, /* Enable FET */ | |
48 | }; | |
49 | ||
50 | /** | |
51 | * tps65090_read - read a byte from tps6090 | |
52 | * | |
53 | * @param reg The register address to read from. | |
54 | * @param val We'll return value value read here. | |
55 | * @return 0 if ok; error if EC returns failure. | |
56 | */ | |
57 | static int tps65090_read(u32 reg, u8 *val) | |
58 | { | |
cc456bd7 SG |
59 | return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, |
60 | val, 1, true); | |
2c94611d SG |
61 | } |
62 | ||
63 | /** | |
64 | * tps65090_write - write a byte to tps6090 | |
65 | * | |
66 | * @param reg The register address to write to. | |
67 | * @param val The value to write. | |
68 | * @return 0 if ok; error if EC returns failure. | |
69 | */ | |
70 | static int tps65090_write(u32 reg, u8 val) | |
71 | { | |
cc456bd7 SG |
72 | return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, |
73 | &val, 1, false); | |
2c94611d SG |
74 | } |
75 | ||
76 | /** | |
77 | * Checks for a valid FET number | |
78 | * | |
79 | * @param fet_id FET number to check | |
80 | * @return 0 if ok, -EINVAL if FET value is out of range | |
81 | */ | |
82 | static int tps65090_check_fet(unsigned int fet_id) | |
83 | { | |
84 | if (fet_id == 0 || fet_id > MAX_FET_NUM) { | |
85 | debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", | |
86 | fet_id, MAX_FET_NUM); | |
87 | return -EINVAL; | |
88 | } | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | /** | |
94 | * Set the power state for a FET | |
95 | * | |
96 | * @param fet_id Fet number to set (1..MAX_FET_NUM) | |
97 | * @param set 1 to power on FET, 0 to power off | |
98 | * @return -EIO if we got a comms error, -EAGAIN if the FET failed to | |
99 | * change state. If all is ok, returns 0. | |
100 | */ | |
101 | static int tps65090_fet_set(int fet_id, bool set) | |
102 | { | |
103 | int retry; | |
104 | u8 reg, value; | |
105 | ||
106 | value = FET_CTRL_ADENFET | FET_CTRL_WAIT; | |
107 | if (set) | |
108 | value |= FET_CTRL_ENFET; | |
109 | ||
110 | if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value)) | |
111 | return -EIO; | |
112 | ||
113 | /* Try reading until we get a result */ | |
114 | for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { | |
115 | if (tps65090_read(REG_FET1_CTRL + fet_id - 1, ®)) | |
116 | return -EIO; | |
117 | ||
118 | /* Check that the fet went into the expected state */ | |
119 | if (!!(reg & FET_CTRL_PGFET) == set) | |
120 | return 0; | |
121 | ||
122 | /* If we got a timeout, there is no point in waiting longer */ | |
123 | if (reg & FET_CTRL_TOFET) | |
124 | break; | |
125 | ||
126 | mdelay(1); | |
127 | } | |
128 | ||
129 | debug("FET %d: Power good should have set to %d but reg=%#02x\n", | |
130 | fet_id, set, reg); | |
131 | return -EAGAIN; | |
132 | } | |
133 | ||
134 | int tps65090_fet_enable(unsigned int fet_id) | |
135 | { | |
136 | ulong start; | |
137 | int loops; | |
138 | int ret; | |
139 | ||
140 | ret = tps65090_check_fet(fet_id); | |
141 | if (ret) | |
142 | return ret; | |
143 | ||
144 | start = get_timer(0); | |
145 | for (loops = 0;; loops++) { | |
146 | ret = tps65090_fet_set(fet_id, true); | |
147 | if (!ret) | |
148 | break; | |
149 | ||
150 | if (get_timer(start) > 100) | |
151 | break; | |
152 | ||
153 | /* Turn it off and try again until we time out */ | |
154 | tps65090_fet_set(fet_id, false); | |
155 | } | |
156 | ||
157 | if (ret) { | |
158 | debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", | |
159 | __func__, fet_id, get_timer(start), loops); | |
160 | } else if (loops) { | |
161 | debug("%s: FET%d powered on after %lums, loops=%d\n", | |
162 | __func__, fet_id, get_timer(start), loops); | |
163 | } | |
164 | /* | |
165 | * Unfortunately, there are some conditions where the power | |
166 | * good bit will be 0, but the fet still comes up. One such | |
167 | * case occurs with the lcd backlight. We'll just return 0 here | |
168 | * and assume that the fet will eventually come up. | |
169 | */ | |
170 | if (ret == -EAGAIN) | |
171 | ret = 0; | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
176 | int tps65090_fet_disable(unsigned int fet_id) | |
177 | { | |
178 | int ret; | |
179 | ||
180 | ret = tps65090_check_fet(fet_id); | |
181 | if (ret) | |
182 | return ret; | |
183 | ||
184 | ret = tps65090_fet_set(fet_id, false); | |
185 | ||
186 | return ret; | |
187 | } | |
188 | ||
189 | int tps65090_fet_is_enabled(unsigned int fet_id) | |
190 | { | |
191 | u8 reg = 0; | |
192 | int ret; | |
193 | ||
194 | ret = tps65090_check_fet(fet_id); | |
195 | if (ret) | |
196 | return ret; | |
197 | ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, ®); | |
198 | if (ret) { | |
199 | debug("fail to read FET%u_CTRL register over I2C", fet_id); | |
200 | return -EIO; | |
201 | } | |
202 | ||
203 | return reg & FET_CTRL_ENFET; | |
204 | } | |
205 | ||
206 | int tps65090_init(void) | |
207 | { | |
208 | puts("TPS65090 PMIC EC init\n"); | |
209 | ||
210 | config.dev = board_get_cros_ec_dev(); | |
211 | if (!config.dev) { | |
212 | debug("%s: no cros_ec device: cannot init tps65090\n", | |
213 | __func__); | |
214 | return -ENODEV; | |
215 | } | |
216 | ||
217 | return 0; | |
218 | } |