uboot/drivers/power/regulator/tps65090_regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <errno.h>
   9#include <log.h>
  10#include <linux/delay.h>
  11#include <power/pmic.h>
  12#include <power/regulator.h>
  13#include <power/tps65090.h>
  14
  15static int tps65090_fet_probe(struct udevice *dev)
  16{
  17        struct dm_regulator_uclass_plat *uc_pdata;
  18
  19        uc_pdata = dev_get_uclass_plat(dev);
  20
  21        uc_pdata->type = REGULATOR_TYPE_OTHER;
  22        uc_pdata->mode_count = 0;
  23
  24        return 0;
  25}
  26
  27static int tps65090_fet_get_enable(struct udevice *dev)
  28{
  29        struct udevice *pmic = dev_get_parent(dev);
  30        int ret, fet_id;
  31
  32        fet_id = dev->driver_data;
  33        debug("%s: fet_id=%d\n", __func__, fet_id);
  34
  35        ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
  36        if (ret < 0)
  37                return ret;
  38
  39        return ret & FET_CTRL_ENFET;
  40}
  41
  42/**
  43 * Set the power state for a FET
  44 *
  45 * @param pmic          pmic structure for the tps65090
  46 * @param fet_id        FET number to set (1..MAX_FET_NUM)
  47 * @param set           1 to power on FET, 0 to power off
  48 * @return -EIO if we got a comms error, -EAGAIN if the FET failed to
  49 * change state. If all is ok, returns 0.
  50 */
  51static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set)
  52{
  53        int retry;
  54        u32 value;
  55        int ret;
  56
  57        value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
  58        if (set)
  59                value |= FET_CTRL_ENFET;
  60
  61        if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value))
  62                return -EIO;
  63
  64        /* Try reading until we get a result */
  65        for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
  66                ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
  67                if (ret < 0)
  68                        return ret;
  69
  70                /* Check that the FET went into the expected state */
  71                debug("%s: flags=%x\n", __func__, ret);
  72                if (!!(ret & FET_CTRL_PGFET) == set)
  73                        return 0;
  74
  75                /* If we got a timeout, there is no point in waiting longer */
  76                if (ret & FET_CTRL_TOFET)
  77                        break;
  78
  79                mdelay(1);
  80        }
  81
  82        debug("FET %d: Power good should have set to %d but reg=%#02x\n",
  83              fet_id, set, ret);
  84        return -EAGAIN;
  85}
  86
  87static int tps65090_fet_set_enable(struct udevice *dev, bool enable)
  88{
  89        struct udevice *pmic = dev_get_parent(dev);
  90        int ret, fet_id;
  91        ulong start;
  92        int loops;
  93
  94        fet_id = dev->driver_data;
  95        debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable);
  96
  97        start = get_timer(0);
  98        for (loops = 0;; loops++) {
  99                ret = tps65090_fet_set(pmic, fet_id, enable);
 100                if (!ret)
 101                        break;
 102
 103                if (get_timer(start) > 100)
 104                        break;
 105
 106                /* Turn it off and try again until we time out */
 107                tps65090_fet_set(pmic, fet_id, false);
 108        }
 109
 110        if (ret)
 111                debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
 112                      __func__, fet_id, get_timer(start), loops);
 113        else if (loops)
 114                debug("%s: FET%d powered on after %lums, loops=%d\n",
 115                      __func__, fet_id, get_timer(start), loops);
 116
 117        /*
 118         * Unfortunately there are some conditions where the power-good bit
 119         * will be 0, but the FET still comes up. One such case occurs with
 120         * the LCD backlight on snow. We'll just return 0 here and assume
 121         * that the FET will eventually come up.
 122         */
 123        if (ret == -EAGAIN)
 124                ret = 0;
 125
 126        return ret;
 127}
 128
 129static const struct dm_regulator_ops tps65090_fet_ops = {
 130        .get_enable = tps65090_fet_get_enable,
 131        .set_enable = tps65090_fet_set_enable,
 132};
 133
 134U_BOOT_DRIVER(tps65090_fet) = {
 135        .name = TPS65090_FET_DRIVER,
 136        .id = UCLASS_REGULATOR,
 137        .ops = &tps65090_fet_ops,
 138        .probe = tps65090_fet_probe,
 139};
 140