WIP patch to enable cros-ec on peach_pit. Signed-off-by: Simon Glass <s...@chromium.org> --- drivers/misc/cros_ec_spi.c | 4 +- drivers/power/pmic/Makefile | 3 +- drivers/power/pmic/pmic_tps65090_ec.c | 212 ++++++++++++++++++++++++++++++++++ drivers/spi/exynos_spi.c | 9 +- drivers/spi/spi.c | 2 + include/configs/exynos5-dt.h | 2 +- include/configs/peach-pit.h | 2 + include/power/tps65090_pmic.h | 6 + 8 files changed, 232 insertions(+), 8 deletions(-) create mode 100644 drivers/power/pmic/pmic_tps65090_ec.c
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c index 7df709c..015333f 100644 --- a/drivers/misc/cros_ec_spi.c +++ b/drivers/misc/cros_ec_spi.c @@ -98,7 +98,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, } out = dev->dout; - out[0] = cmd_version; + out[0] = EC_CMD_VERSION0 + cmd_version; out[1] = cmd; out[2] = (uint8_t)dout_len; memcpy(out + 3, dout, dout_len); @@ -165,7 +165,7 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) */ int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob) { - dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, dev->node); + dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node); if (!dev->spi) { debug("%s: Could not setup SPI slave\n", __func__); return -1; diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index a472f61..e7b07eb 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o 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_I2C) += 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/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index c92276f..2969184 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -428,10 +428,6 @@ void spi_cs_activate(struct spi_slave *slave) clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); debug("Activate CS, bus %d\n", spi_slave->slave.bus); spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE; - - /* Remember time of this transaction so we can honour the bus delay */ - if (spi_slave->bus->deactivate_delay_us) - spi_slave->last_transaction_us = timer_get_us(); } /** @@ -445,6 +441,11 @@ void spi_cs_deactivate(struct spi_slave *slave) struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); + + /* Remember time of this transaction so we can honour the bus delay */ + if (spi_slave->bus->deactivate_delay_us) + spi_slave->last_transaction_us = timer_get_us(); + debug("Deactivate CS, bus %d\n", spi_slave->slave.bus); } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7ddea9b..7d81fbd 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -53,6 +53,8 @@ struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum, mode |= SPI_CPHA; if (fdtdec_get_bool(blob, node, "spi-cs-high")) mode |= SPI_CS_HIGH; + if (fdtdec_get_bool(blob, node, "spi-half-duplex")) + mode |= SPI_PREAMBLE; return spi_setup_slave(busnum, cs, max_hz, mode); } #endif diff --git a/include/configs/exynos5-dt.h b/include/configs/exynos5-dt.h index e36a031..4e316b9 100644 --- a/include/configs/exynos5-dt.h +++ b/include/configs/exynos5-dt.h @@ -37,8 +37,8 @@ #define CONFIG_TRACE_EARLY_ADDR 0x50000000 /* Keep L2 Cache Disabled */ -#define CONFIG_SYS_DCACHE_OFF #define CONFIG_SYS_CACHELINE_SIZE 64 +#define CONFIG_CMD_CACHE /* Enable ACE acceleration for SHA1 and SHA256 */ #define CONFIG_EXYNOS_ACE_SHA diff --git a/include/configs/peach-pit.h b/include/configs/peach-pit.h index 88c093f..01be8a6 100644 --- a/include/configs/peach-pit.h +++ b/include/configs/peach-pit.h @@ -22,6 +22,8 @@ #define CONFIG_SYS_PROMPT "Peach # " #define CONFIG_IDENT_STRING " for Peach" +#define CONFIG_POWER_TPS65090_EC + #define CONFIG_VIDEO_PARADE /* Display */ 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 * -- 1.8.1.2 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot