On Mon, Jul 7, 2014 at 9:46 PM, Simon Glass <s...@chromium.org> wrote: > Unfortunately on Pit the AP has no direct access to the tps65090 but must > talk through the EC (over SPI) to the EC's I2C bus. > > When driver model supports PMICs this will be relatively easy. In the > meantime the best approach is to duplicate the driver. It will be refactored > once driver model support is expanded. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > drivers/power/pmic/Makefile | 1 + > drivers/power/pmic/pmic_tps65090_ec.c | 212 > ++++++++++++++++++++++++++++++++++ > include/power/tps65090_pmic.h | 6 + > 3 files changed, 219 insertions(+) > create mode 100644 drivers/power/pmic/pmic_tps65090_ec.c > > diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile > index a472f61..0b76611 100644 > --- a/drivers/power/pmic/Makefile > +++ b/drivers/power/pmic/Makefile > @@ -12,6 +12,7 @@ obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o > obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o > obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o > obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o > +obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o > obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o > obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o > obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o > diff --git a/drivers/power/pmic/pmic_tps65090_ec.c > b/drivers/power/pmic/pmic_tps65090_ec.c > new file mode 100644 > index 0000000..93b7923 > --- /dev/null > +++ b/drivers/power/pmic/pmic_tps65090_ec.c > @@ -0,0 +1,212 @@ > +/* > + * Copyright (c) 2013 The Chromium OS Authors. All rights reserved. > + * Use of this source code is governed by a BSD-style license that can be > + * found in the LICENSE file. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + */ > + > +#include <common.h> > +#include <cros_ec.h> > +#include <errno.h> > +#include <power/tps65090_pmic.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#define TPS65090_ADDR 0x48 > + > +static struct tps65090 { > + struct cros_ec_dev *dev; /* The CROS_EC device */ > +} config; > + > +/* TPS65090 register addresses */ > +enum { > + REG_FET1_CTRL = 0x0f, > + REG_FET2_CTRL, > + REG_FET3_CTRL, > + REG_FET4_CTRL, > + REG_FET5_CTRL, > + REG_FET6_CTRL, > + REG_FET7_CTRL, > + TPS65090_NUM_REGS, > +}; > + > +enum { > + MAX_FET_NUM = 7, > + MAX_CTRL_READ_TRIES = 5, > + > + /* TPS65090 FET_CTRL register values */ > + FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ > + FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ > + FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ > + FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ > + FET_CTRL_ENFET = 1 << 0, /* Enable FET */ > +}; > + > +/** > + * tps65090_read - read a byte from tps6090 > + * > + * @param reg The register address to read from. > + * @param val We'll return value value read here. > + * @return 0 if ok; error if EC returns failure. > + */ > +static int tps65090_read(u32 reg, u8 *val) > +{ > + return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, > + val, 1, true); > +} > + > +/** > + * tps65090_write - write a byte to tps6090 > + * > + * @param reg The register address to write to. > + * @param val The value to write. > + * @return 0 if ok; error if EC returns failure. > + */ > +static int tps65090_write(u32 reg, u8 val) > +{ > + return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, > + &val, 1, false); > +} > + > +/** > + * Checks for a valid FET number > + * > + * @param fet_id FET number to check > + * @return 0 if ok, -1 if FET value is out of range > + */ > +static int tps65090_check_fet(unsigned int fet_id) > +{ > + if (fet_id == 0 || fet_id > MAX_FET_NUM) { > + debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", > + fet_id, MAX_FET_NUM); > + return -1; > + } > + > + return 0; > +} > + > +/** > + * Set the power state for a FET > + * > + * @param fet_id Fet number to set (1..MAX_FET_NUM) > + * @param set 1 to power on FET, 0 to power off > + * @return FET_ERR_COMMS if we got a comms error, FET_ERR_NOT_READY if the > + * FET failed to change state. If all is ok, returns 0. > + */ > +static int tps65090_fet_set(int fet_id, int set) > +{ > + int retry; > + u8 reg = 0, value; > + > + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; > + if (set) > + value |= FET_CTRL_ENFET; > + > + if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value)) > + return FET_ERR_COMMS; > + /* Try reading until we get a result */ > + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { > + if (tps65090_read(REG_FET1_CTRL + fet_id - 1, ®)) > + return FET_ERR_COMMS; > + > + /* Check that the fet went into the expected state */ > + if (!!(reg & FET_CTRL_PGFET) == set) > + return 0; > + > + /* If we got a timeout, there is no point in waiting longer */ > + if (reg & FET_CTRL_TOFET) > + break; > + > + mdelay(1); > + } > + > + debug("FET %d: Power good should have set to %d but reg=%#02x\n", > + fet_id, set, reg); > + return FET_ERR_NOT_READY; > +} > + > +int tps65090_fet_enable(unsigned int fet_id) > +{ > + int loops; > + ulong start; > + int ret = 0; > + > + if (tps65090_check_fet(fet_id)) > + return -1; > + > + start = get_timer(0); > + for (loops = 0; ; loops++) { > + ret = tps65090_fet_set(fet_id, 1); > + if (!ret) > + break; > + > + if (get_timer(start) > 100) > + break; > + > + /* Turn it off and try again until we time out */ > + tps65090_fet_set(fet_id, 0); > + } > + > + if (ret) { > + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", > + __func__, fet_id, get_timer(start), loops); > + } else if (loops) { > + debug("%s: FET%d powered on after %lums, loops=%d\n", > + __func__, fet_id, get_timer(start), loops); > + } > + /* > + * Unfortunately, there are some conditions where the power > + * good bit will be 0, but the fet still comes up. One such > + * case occurs with the lcd backlight. We'll just return 0 here > + * and assume that the fet will eventually come up. > + */ > + if (ret == FET_ERR_NOT_READY) > + ret = 0; > + > + return ret; > +} > + > +int tps65090_fet_disable(unsigned int fet_id) > +{ > + int ret; > + > + if (tps65090_check_fet(fet_id)) > + return -1; > + > + ret = tps65090_fet_set(fet_id, 0); > + > + return ret; > +} > + > +int tps65090_fet_is_enabled(unsigned int fet_id) > +{ > + u8 reg = 0; > + int ret; > + > + if (tps65090_check_fet(fet_id)) > + return -1; > + ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, ®); > + if (ret) { > + debug("fail to read FET%u_CTRL register over I2C", fet_id); > + return -2; > + } > + > + return reg & FET_CTRL_ENFET; > +} > + > +int tps65090_init(void) > +{ > + puts("TPS65090 PMIC EC init\n"); > + > + config.dev = board_get_cros_ec_dev(); > + if (!config.dev) { > + debug("%s: no cros_ec device: cannot init tps65090\n", > + __func__); > + return -1; > + } > + > + return 0; > +} > diff --git a/include/power/tps65090_pmic.h b/include/power/tps65090_pmic.h > index dcf99c9..531751d 100644 > --- a/include/power/tps65090_pmic.h > +++ b/include/power/tps65090_pmic.h > @@ -18,6 +18,12 @@ enum { > TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT, > }; > > +/* FET errors */ > +enum { > + FET_ERR_COMMS = -1, /* FET comms error */ > + FET_ERR_NOT_READY = -2, /* FET is not yet ready - retry */ > +}; > + > /** > * Enable FET > * > -- > 2.0.0.526.g5318336 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot Able to test display on peach_pit(which needs tps65090) with these patches. Also, crosec commands from u-boot prompt works as expected on peach_pit.
Tested-by: Ajay Kumar <ajaykumar...@samsung.com> _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot