11c88b67eSSimon Glass /*
21c88b67eSSimon Glass * Copyright (c) 2015 Google, Inc
31c88b67eSSimon Glass *
41c88b67eSSimon Glass * SPDX-License-Identifier: GPL-2.0+
51c88b67eSSimon Glass */
61c88b67eSSimon Glass
71c88b67eSSimon Glass #include <common.h>
81c88b67eSSimon Glass #include <dm.h>
91c88b67eSSimon Glass #include <errno.h>
101c88b67eSSimon Glass #include <power/pmic.h>
111c88b67eSSimon Glass #include <power/regulator.h>
121c88b67eSSimon Glass #include <power/tps65090.h>
131c88b67eSSimon Glass
tps65090_fet_probe(struct udevice * dev)141c88b67eSSimon Glass static int tps65090_fet_probe(struct udevice *dev)
151c88b67eSSimon Glass {
161c88b67eSSimon Glass struct dm_regulator_uclass_platdata *uc_pdata;
171c88b67eSSimon Glass
181c88b67eSSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
191c88b67eSSimon Glass
201c88b67eSSimon Glass uc_pdata->type = REGULATOR_TYPE_OTHER;
211c88b67eSSimon Glass uc_pdata->mode_count = 0;
221c88b67eSSimon Glass
231c88b67eSSimon Glass return 0;
241c88b67eSSimon Glass }
251c88b67eSSimon Glass
tps65090_fet_get_enable(struct udevice * dev)26*2a4747d3SKeerthy static int tps65090_fet_get_enable(struct udevice *dev)
271c88b67eSSimon Glass {
281c88b67eSSimon Glass struct udevice *pmic = dev_get_parent(dev);
291c88b67eSSimon Glass int ret, fet_id;
301c88b67eSSimon Glass
311c88b67eSSimon Glass fet_id = dev->driver_data;
321c88b67eSSimon Glass debug("%s: fet_id=%d\n", __func__, fet_id);
331c88b67eSSimon Glass
341c88b67eSSimon Glass ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
351c88b67eSSimon Glass if (ret < 0)
361c88b67eSSimon Glass return ret;
371c88b67eSSimon Glass
381c88b67eSSimon Glass return ret & FET_CTRL_ENFET;
391c88b67eSSimon Glass }
401c88b67eSSimon Glass
411c88b67eSSimon Glass /**
421c88b67eSSimon Glass * Set the power state for a FET
431c88b67eSSimon Glass *
441c88b67eSSimon Glass * @param pmic pmic structure for the tps65090
451c88b67eSSimon Glass * @param fet_id FET number to set (1..MAX_FET_NUM)
461c88b67eSSimon Glass * @param set 1 to power on FET, 0 to power off
471c88b67eSSimon Glass * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
481c88b67eSSimon Glass * change state. If all is ok, returns 0.
491c88b67eSSimon Glass */
tps65090_fet_set(struct udevice * pmic,int fet_id,bool set)501c88b67eSSimon Glass static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set)
511c88b67eSSimon Glass {
521c88b67eSSimon Glass int retry;
531c88b67eSSimon Glass u32 value;
541c88b67eSSimon Glass int ret;
551c88b67eSSimon Glass
561c88b67eSSimon Glass value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
571c88b67eSSimon Glass if (set)
581c88b67eSSimon Glass value |= FET_CTRL_ENFET;
591c88b67eSSimon Glass
601c88b67eSSimon Glass if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value))
611c88b67eSSimon Glass return -EIO;
621c88b67eSSimon Glass
631c88b67eSSimon Glass /* Try reading until we get a result */
641c88b67eSSimon Glass for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
651c88b67eSSimon Glass ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
661c88b67eSSimon Glass if (ret < 0)
671c88b67eSSimon Glass return ret;
681c88b67eSSimon Glass
691c88b67eSSimon Glass /* Check that the FET went into the expected state */
701c88b67eSSimon Glass debug("%s: flags=%x\n", __func__, ret);
711c88b67eSSimon Glass if (!!(ret & FET_CTRL_PGFET) == set)
721c88b67eSSimon Glass return 0;
731c88b67eSSimon Glass
741c88b67eSSimon Glass /* If we got a timeout, there is no point in waiting longer */
751c88b67eSSimon Glass if (ret & FET_CTRL_TOFET)
761c88b67eSSimon Glass break;
771c88b67eSSimon Glass
781c88b67eSSimon Glass mdelay(1);
791c88b67eSSimon Glass }
801c88b67eSSimon Glass
811c88b67eSSimon Glass debug("FET %d: Power good should have set to %d but reg=%#02x\n",
821c88b67eSSimon Glass fet_id, set, ret);
831c88b67eSSimon Glass return -EAGAIN;
841c88b67eSSimon Glass }
851c88b67eSSimon Glass
tps65090_fet_set_enable(struct udevice * dev,bool enable)861c88b67eSSimon Glass static int tps65090_fet_set_enable(struct udevice *dev, bool enable)
871c88b67eSSimon Glass {
881c88b67eSSimon Glass struct udevice *pmic = dev_get_parent(dev);
891c88b67eSSimon Glass int ret, fet_id;
901c88b67eSSimon Glass ulong start;
911c88b67eSSimon Glass int loops;
921c88b67eSSimon Glass
931c88b67eSSimon Glass fet_id = dev->driver_data;
941c88b67eSSimon Glass debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable);
951c88b67eSSimon Glass
961c88b67eSSimon Glass start = get_timer(0);
971c88b67eSSimon Glass for (loops = 0;; loops++) {
981c88b67eSSimon Glass ret = tps65090_fet_set(pmic, fet_id, enable);
991c88b67eSSimon Glass if (!ret)
1001c88b67eSSimon Glass break;
1011c88b67eSSimon Glass
1021c88b67eSSimon Glass if (get_timer(start) > 100)
1031c88b67eSSimon Glass break;
1041c88b67eSSimon Glass
1051c88b67eSSimon Glass /* Turn it off and try again until we time out */
1061c88b67eSSimon Glass tps65090_fet_set(pmic, fet_id, false);
1071c88b67eSSimon Glass }
1081c88b67eSSimon Glass
1091c88b67eSSimon Glass if (ret)
1101c88b67eSSimon Glass debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
1111c88b67eSSimon Glass __func__, fet_id, get_timer(start), loops);
1121c88b67eSSimon Glass else if (loops)
1131c88b67eSSimon Glass debug("%s: FET%d powered on after %lums, loops=%d\n",
1141c88b67eSSimon Glass __func__, fet_id, get_timer(start), loops);
1151c88b67eSSimon Glass
1161c88b67eSSimon Glass /*
1171c88b67eSSimon Glass * Unfortunately there are some conditions where the power-good bit
1181c88b67eSSimon Glass * will be 0, but the FET still comes up. One such case occurs with
1191c88b67eSSimon Glass * the LCD backlight on snow. We'll just return 0 here and assume
1201c88b67eSSimon Glass * that the FET will eventually come up.
1211c88b67eSSimon Glass */
1221c88b67eSSimon Glass if (ret == -EAGAIN)
1231c88b67eSSimon Glass ret = 0;
1241c88b67eSSimon Glass
1251c88b67eSSimon Glass return ret;
1261c88b67eSSimon Glass }
1271c88b67eSSimon Glass
1281c88b67eSSimon Glass static const struct dm_regulator_ops tps65090_fet_ops = {
1291c88b67eSSimon Glass .get_enable = tps65090_fet_get_enable,
1301c88b67eSSimon Glass .set_enable = tps65090_fet_set_enable,
1311c88b67eSSimon Glass };
1321c88b67eSSimon Glass
1331c88b67eSSimon Glass U_BOOT_DRIVER(tps65090_fet) = {
1341c88b67eSSimon Glass .name = TPS65090_FET_DRIVER,
1351c88b67eSSimon Glass .id = UCLASS_REGULATOR,
1361c88b67eSSimon Glass .ops = &tps65090_fet_ops,
1371c88b67eSSimon Glass .probe = tps65090_fet_probe,
1381c88b67eSSimon Glass };
139