aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Anderson <dianders@chromium.org>2014-04-23 11:56:05 -0400
committerMark Brown <broonie@linaro.org>2014-04-29 13:05:07 -0400
commited11f1ead54bf0398a4303b51125622113c9c9e1 (patch)
tree0b0a02f34e7cc13bbdb153685a3ba1888f9b63e8
parent3e93457b45a1a8c69227ce596ee2005fa06f20dd (diff)
regulator: tps65090: Make FETs more reliable by adding retries
An issue was discovered with tps65090 where sometimes the FETs wouldn't actually turn on when requested (they would report overcurrent). The most problematic FET was the one used for the LCD backlight on the Samsung ARM Chromebook (FET1). Problems were especially prevalent when the device was plugged in to AC power (when the backlight voltage was higher). Mitigate the problem by adding retries on the enables of the FETs, which works around the problem fairly effectively. Signed-off-by: Doug Anderson <dianders@chromium.org> Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Michael Spang <spang@chromium.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/regulator/tps65090-regulator.c155
1 files changed, 140 insertions, 15 deletions
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index ca04e9f010e1..2057e2e311de 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -17,6 +17,7 @@
17 */ 17 */
18 18
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/delay.h>
20#include <linux/init.h> 21#include <linux/init.h>
21#include <linux/gpio.h> 22#include <linux/gpio.h>
22#include <linux/of_gpio.h> 23#include <linux/of_gpio.h>
@@ -28,7 +29,13 @@
28#include <linux/regulator/of_regulator.h> 29#include <linux/regulator/of_regulator.h>
29#include <linux/mfd/tps65090.h> 30#include <linux/mfd/tps65090.h>
30 31
32#define MAX_CTRL_READ_TRIES 5
33#define MAX_FET_ENABLE_TRIES 1000
34
35#define CTRL_EN_BIT 0 /* Regulator enable bit, active high */
31#define CTRL_WT_BIT 2 /* Regulator wait time 0 bit */ 36#define CTRL_WT_BIT 2 /* Regulator wait time 0 bit */
37#define CTRL_PG_BIT 4 /* Regulator power good bit, 1=good */
38#define CTRL_TO_BIT 7 /* Regulator timeout bit, 1=wait */
32 39
33#define MAX_OVERCURRENT_WAIT 3 /* Overcurrent wait must be <= this */ 40#define MAX_OVERCURRENT_WAIT 3 /* Overcurrent wait must be <= this */
34 41
@@ -80,40 +87,158 @@ static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri,
80 return ret; 87 return ret;
81} 88}
82 89
83static struct regulator_ops tps65090_reg_contol_ops = { 90/**
91 * tps65090_try_enable_fet - Try to enable a FET
92 *
93 * @rdev: Regulator device
94 *
95 * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get
96 * set, or some other -ve value if another error occurred (e.g. i2c error)
97 */
98static int tps65090_try_enable_fet(struct regulator_dev *rdev)
99{
100 unsigned int control;
101 int ret, i;
102
103 ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
104 rdev->desc->enable_mask,
105 rdev->desc->enable_mask);
106 if (ret < 0) {
107 dev_err(&rdev->dev, "Error in updating reg %#x\n",
108 rdev->desc->enable_reg);
109 return ret;
110 }
111
112 for (i = 0; i < MAX_CTRL_READ_TRIES; i++) {
113 ret = regmap_read(rdev->regmap, rdev->desc->enable_reg,
114 &control);
115 if (ret < 0)
116 return ret;
117
118 if (!(control & BIT(CTRL_TO_BIT)))
119 break;
120
121 usleep_range(1000, 1500);
122 }
123 if (!(control & BIT(CTRL_PG_BIT)))
124 return -ENOTRECOVERABLE;
125
126 return 0;
127}
128
129/**
130 * tps65090_fet_enable - Enable a FET, trying a few times if it fails
131 *
132 * Some versions of the tps65090 have issues when turning on the FETs.
133 * This function goes through several steps to ensure the best chance of the
134 * FET going on. Specifically:
135 * - We'll make sure that we bump the "overcurrent wait" to the maximum, which
136 * increases the chances that we'll turn on properly.
137 * - We'll retry turning the FET on multiple times (turning off in between).
138 *
139 * @rdev: Regulator device
140 *
141 * Return: 0 if ok, non-zero if it fails.
142 */
143static int tps65090_fet_enable(struct regulator_dev *rdev)
144{
145 int ret, tries;
146
147 /*
148 * Try enabling multiple times until we succeed since sometimes the
149 * first try times out.
150 */
151 tries = 0;
152 while (true) {
153 ret = tps65090_try_enable_fet(rdev);
154 if (!ret)
155 break;
156 if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES)
157 goto err;
158
159 /* Try turning the FET off (and then on again) */
160 ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
161 rdev->desc->enable_mask, 0);
162 if (ret)
163 goto err;
164
165 tries++;
166 }
167
168 if (tries)
169 dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n",
170 rdev->desc->enable_reg, tries);
171
172 return 0;
173err:
174 dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg);
175 WARN_ON(1);
176
177 return ret;
178}
179
180static struct regulator_ops tps65090_reg_control_ops = {
84 .enable = regulator_enable_regmap, 181 .enable = regulator_enable_regmap,
85 .disable = regulator_disable_regmap, 182 .disable = regulator_disable_regmap,
86 .is_enabled = regulator_is_enabled_regmap, 183 .is_enabled = regulator_is_enabled_regmap,
87}; 184};
88 185
186static struct regulator_ops tps65090_fet_control_ops = {
187 .enable = tps65090_fet_enable,
188 .disable = regulator_disable_regmap,
189 .is_enabled = regulator_is_enabled_regmap,
190};
191
89static struct regulator_ops tps65090_ldo_ops = { 192static struct regulator_ops tps65090_ldo_ops = {
90}; 193};
91 194
92#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ 195#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _ops) \
93{ \ 196{ \
94 .name = "TPS65090_RAILS"#_id, \ 197 .name = "TPS65090_RAILS"#_id, \
95 .supply_name = _sname, \ 198 .supply_name = _sname, \
96 .id = TPS65090_REGULATOR_##_id, \ 199 .id = TPS65090_REGULATOR_##_id, \
97 .ops = &_ops, \ 200 .ops = &_ops, \
98 .enable_reg = _en_reg, \ 201 .enable_reg = _en_reg, \
99 .enable_mask = BIT(0), \ 202 .enable_val = _en_bits, \
203 .enable_mask = _en_bits, \
100 .type = REGULATOR_VOLTAGE, \ 204 .type = REGULATOR_VOLTAGE, \
101 .owner = THIS_MODULE, \ 205 .owner = THIS_MODULE, \
102} 206}
103 207
104static struct regulator_desc tps65090_regulator_desc[] = { 208static struct regulator_desc tps65090_regulator_desc[] = {
105 tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops), 209 tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, BIT(CTRL_EN_BIT),
106 tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops), 210 tps65090_reg_control_ops),
107 tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops), 211 tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, BIT(CTRL_EN_BIT),
108 tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops), 212 tps65090_reg_control_ops),
109 tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops), 213 tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, BIT(CTRL_EN_BIT),
110 tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops), 214 tps65090_reg_control_ops),
111 tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops), 215
112 tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), 216 tps65090_REG_DESC(FET1, "infet1", 0x0F,
113 tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), 217 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
114 tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), 218 tps65090_fet_control_ops),
115 tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops), 219 tps65090_REG_DESC(FET2, "infet2", 0x10,
116 tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops), 220 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
221 tps65090_fet_control_ops),
222 tps65090_REG_DESC(FET3, "infet3", 0x11,
223 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
224 tps65090_fet_control_ops),
225 tps65090_REG_DESC(FET4, "infet4", 0x12,
226 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
227 tps65090_fet_control_ops),
228 tps65090_REG_DESC(FET5, "infet5", 0x13,
229 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
230 tps65090_fet_control_ops),
231 tps65090_REG_DESC(FET6, "infet6", 0x14,
232 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
233 tps65090_fet_control_ops),
234 tps65090_REG_DESC(FET7, "infet7", 0x15,
235 BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT),
236 tps65090_fet_control_ops),
237
238 tps65090_REG_DESC(LDO1, "vsys-l1", 0, 0,
239 tps65090_ldo_ops),
240 tps65090_REG_DESC(LDO2, "vsys-l2", 0, 0,
241 tps65090_ldo_ops),
117}; 242};
118 243
119static inline bool is_dcdc(int id) 244static inline bool is_dcdc(int id)