]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/power/pmic/pmic_tps65090_ec.c
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / power / pmic / pmic_tps65090_ec.c
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 {
59         return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
60                                 val, 1, true);
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 {
72         return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
73                                 &val, 1, false);
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, &reg))
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, &reg);
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 }