[coreboot-gerrit] New patch to review for coreboot: de318cc [1/2] initial import of TI TPS65090

David Hendricks (dhendrix@chromium.org) gerrit at coreboot.org
Wed Apr 10 03:06:57 CEST 2013


David Hendricks (dhendrix at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3060

-gerrit

commit de318cc8a47ced7bf974604af07b8b96d2199ac8
Author: David Hendricks <dhendrix at chromium.org>
Date:   Tue Apr 9 16:58:02 2013 -0700

    [1/2] initial import of TI TPS65090
    
    This imports TPS65090 PMIC from u-boot and adds/updates Makefiles
    and Kconfig files. The follow-up patch will re-factor the code.
    
    Change-Id: Ic9e43b9665ddf7f55feae8fa17fbf3d2d5f4756d
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
---
 src/drivers/Kconfig                  |   1 +
 src/drivers/Makefile.inc             |   1 +
 src/drivers/ti/Kconfig               |  20 ++
 src/drivers/ti/Makefile.inc          |  20 ++
 src/drivers/ti/tps65090/Kconfig      |  24 +++
 src/drivers/ti/tps65090/Makefile.inc |  20 ++
 src/drivers/ti/tps65090/tps65090.c   | 357 +++++++++++++++++++++++++++++++++++
 src/drivers/ti/tps65090/tps65090.h   |  83 ++++++++
 8 files changed, 526 insertions(+)

diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig
index 315d291..386508a 100644
--- a/src/drivers/Kconfig
+++ b/src/drivers/Kconfig
@@ -33,4 +33,5 @@ endif
 source src/drivers/realtek/Kconfig
 source src/drivers/sil/Kconfig
 source src/drivers/spi/Kconfig
+source src/drivers/ti/Kconfig
 source src/drivers/trident/Kconfig
diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc
index 16d6001..f4fe146 100644
--- a/src/drivers/Makefile.inc
+++ b/src/drivers/Makefile.inc
@@ -29,6 +29,7 @@ subdirs-y += sil
 subdirs-y += trident
 subdirs-y += ics
 subdirs-y += spi
+subdirs-y += ti 
 subdirs-y += ipmi
 subdirs-y += elog
 subdirs-$(CONFIG_ARCH_X86) += pc80
diff --git a/src/drivers/ti/Kconfig b/src/drivers/ti/Kconfig
new file mode 100644
index 0000000..b3aded8
--- /dev/null
+++ b/src/drivers/ti/Kconfig
@@ -0,0 +1,20 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2012 The Chromium OS Authors.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+
+source src/drivers/ti/tps65090/Kconfig
diff --git a/src/drivers/ti/Makefile.inc b/src/drivers/ti/Makefile.inc
new file mode 100644
index 0000000..c0ed9c0
--- /dev/null
+++ b/src/drivers/ti/Makefile.inc
@@ -0,0 +1,20 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2012 The Chromium OS Authors.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+
+subdirs-$(CONFIG_DRIVER_TI_TPS65090) += tps65090/
diff --git a/src/drivers/ti/tps65090/Kconfig b/src/drivers/ti/tps65090/Kconfig
new file mode 100644
index 0000000..feae160
--- /dev/null
+++ b/src/drivers/ti/tps65090/Kconfig
@@ -0,0 +1,24 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2012 The ChromiumOS Authors
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+
+config DRIVER_TI_TPS65090
+	bool
+	default n
+	help
+	  TI TPS65090
diff --git a/src/drivers/ti/tps65090/Makefile.inc b/src/drivers/ti/tps65090/Makefile.inc
new file mode 100644
index 0000000..10b4dd9
--- /dev/null
+++ b/src/drivers/ti/tps65090/Makefile.inc
@@ -0,0 +1,20 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2012 The ChromiumOS Authors
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+
+ramstage-$(CONFIG_DRIVER_TI_TPS65090) += tps65090.c
diff --git a/src/drivers/ti/tps65090/tps65090.c b/src/drivers/ti/tps65090/tps65090.c
new file mode 100644
index 0000000..60b8ec8
--- /dev/null
+++ b/src/drivers/ti/tps65090/tps65090.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2012 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 <fdtdec.h>
+#include <i2c.h>
+#include <tps65090.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* TPS65090 register addresses */
+enum {
+	REG_CG_CTRL0 = 4,
+	REG_CG_STATUS1 = 0xa,
+	REG_FET1_CTRL = 0x0f,
+	REG_FET2_CTRL,
+	REG_FET3_CTRL,
+	REG_FET4_CTRL,
+	REG_FET5_CTRL,
+	REG_FET6_CTRL,
+	REG_FET7_CTRL,
+};
+
+enum {
+	CG_CTRL0_ENC_MASK	= 0x01,
+
+	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 */
+};
+
+static struct tps65090_config {
+	int bus;
+	int addr;
+	int old_bus;
+} config;
+
+/**
+ * Write a value to a register
+ *
+ * @param	chip_addr	i2c slave addr for max77686
+ * @param	reg_addr	register address to write
+ * @param	value		value to be written
+ * @return	0 on success, non-0 on failure
+ */
+static int tps65090_i2c_write(unsigned int reg_addr, unsigned char value)
+{
+	int ret;
+
+	ret = i2c_write(config.addr, reg_addr, 1, &value, 1);
+	debug("%s: reg=%#x, value=%#x, ret=%d\n", __func__, reg_addr, value,
+	      ret);
+	return ret;
+}
+
+/**
+ * Read a value from a register
+ *
+ * @param	chip_addr	i2c addr for max77686
+ * @param	reg_addr	register address to read
+ * @param	value		address to store the value to be read
+ * @return	0 on success, non-0 on failure
+ */
+static int tps65090_i2c_read(unsigned int reg_addr, unsigned char *value)
+{
+	int ret;
+
+	debug("%s: reg=%#x, ", __func__, reg_addr);
+	ret = i2c_read(config.addr, reg_addr, 1, value, 1);
+	if (ret)
+		debug("fail, ret=%d\n", ret);
+	else
+		debug("value=%#x, ret=%d\n", *value, ret);
+	return ret;
+}
+
+static int tps65090_select(void)
+{
+	int ret;
+
+	config.old_bus = i2c_get_bus_num();
+	if (config.old_bus != config.bus) {
+		debug("%s: Select bus %d\n", __func__, config.bus);
+		ret = i2c_set_bus_num(config.bus);
+		if (ret) {
+			debug("%s: Cannot select TPS65090, err %d\n",
+			      __func__, ret);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int tps65090_deselect(void)
+{
+	int ret;
+
+	if (config.old_bus != i2c_get_bus_num()) {
+		ret = i2c_set_bus_num(config.old_bus);
+		debug("%s: Select bus %d\n", __func__, config.old_bus);
+		if (ret) {
+			debug("%s: Cannot restore i2c bus, err %d\n",
+			      __func__, ret);
+			return -1;
+		}
+	}
+	config.old_bus = -1;
+	return 0;
+}
+
+/**
+ * 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, value;
+	uchar reg;
+
+	value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
+	if (set)
+		value |= FET_CTRL_ENFET;
+
+	if (tps65090_i2c_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_i2c_read(REG_FET1_CTRL + fet_id - 1, &reg))
+			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;
+	if (tps65090_select())
+		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);
+	}
+	tps65090_deselect();
+
+	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;
+	if (tps65090_select())
+		return -1;
+	ret = tps65090_fet_set(fet_id, 0);
+	tps65090_deselect();
+
+	return ret;
+}
+
+int tps65090_fet_is_enabled(unsigned int fet_id)
+{
+	unsigned char reg;
+	int ret;
+
+	if (tps65090_check_fet(fet_id))
+		return -1;
+	if (tps65090_select())
+		return -1;
+	ret = tps65090_i2c_read(REG_FET1_CTRL + fet_id - 1, &reg);
+	tps65090_deselect();
+	if (ret) {
+		debug("fail to read FET%u_CTRL register over I2C", fet_id);
+		return -2;
+	}
+
+	return reg & FET_CTRL_ENFET;
+}
+
+int tps65090_get_charging(void)
+{
+	unsigned char val;
+	int ret;
+
+	if (tps65090_select())
+		return -1;
+	ret = tps65090_i2c_read(REG_CG_CTRL0, &val);
+	tps65090_deselect();
+	if (ret)
+		return ret;
+	return val & CG_CTRL0_ENC_MASK ? 1 : 0;
+}
+
+int tps65090_set_charge_enable(int enable)
+{
+	unsigned char val;
+	int ret;
+
+	if (tps65090_select())
+		return -1;
+	ret = tps65090_i2c_read(REG_CG_CTRL0, &val);
+	if (!ret) {
+		if (enable)
+			val |= CG_CTRL0_ENC_MASK;
+		else
+			val &= ~CG_CTRL0_ENC_MASK;
+		ret = tps65090_i2c_write(REG_CG_CTRL0, val);
+	}
+	tps65090_deselect();
+	if (ret) {
+		debug("%s: Failed to read/write register\n", __func__);
+		return ret;
+	}
+	return 0;
+}
+
+int tps65090_get_status(void)
+{
+	unsigned char val;
+	int ret;
+
+	if (tps65090_select())
+		return -1;
+	ret = tps65090_i2c_read(REG_CG_STATUS1, &val);
+	tps65090_deselect();
+	if (ret)
+		return ret;
+	return val;
+}
+
+static int tps65090_decode_config(struct tps65090_config *config)
+{
+#ifdef CONFIG_OF_CONTROL
+	const void *blob = gd->fdt_blob;
+	int node, parent;
+	int i2c_bus;
+
+	node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090);
+	if (node < 0) {
+		debug("%s: Node not found\n", __func__);
+		return -1;
+	}
+	parent = fdt_parent_offset(blob, node);
+	if (parent < 0) {
+		debug("%s: Cannot find node parent\n", __func__);
+		return -1;
+	}
+	i2c_bus = i2c_get_bus_num_fdt(blob, parent);
+	if (i2c_bus < 0)
+		return -1;
+	config->bus = i2c_bus;
+	config->addr = fdtdec_get_addr(blob, node, "reg");
+#else
+	config->bus = CONFIG_TPS65090_I2C_BUS;
+	config->addr = TPS65090_I2C_ADDR;
+#endif
+	return 0;
+}
+
+int tps65090_init(void)
+{
+	int ret;
+
+	if (tps65090_decode_config(&config))
+		return -1;
+
+	config.old_bus = -1;
+
+	if (tps65090_select())
+		return -1;
+
+	/* Probe the chip */
+	ret = i2c_probe(config.addr);
+	if (ret)
+		debug("%s: failed to probe TPS65090 over I2C, returned %d\n",
+		      __func__, ret);
+
+	return ret;
+}
diff --git a/src/drivers/ti/tps65090/tps65090.h b/src/drivers/ti/tps65090/tps65090.h
new file mode 100644
index 0000000..b008a55
--- /dev/null
+++ b/src/drivers/ti/tps65090/tps65090.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+#ifndef __TPS65090_H_
+#define __TPS65090_H_
+
+/* I2C device address for TPS65090 PMU */
+#define TPS65090_I2C_ADDR	0x48
+
+enum {
+	/* Status register fields */
+	TPS65090_ST1_OTC	= 1 << 0,
+	TPS65090_ST1_OCC	= 1 << 1,
+	TPS65090_ST1_STATE_SHIFT = 4,
+	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
+ *
+ * @param	fet_id	FET ID, value between 1 and 7
+ * @return	0 on success, non-0 on failure
+ */
+int tps65090_fet_enable(unsigned int fet_id);
+
+/**
+ * Disable FET
+ *
+ * @param	fet_id	FET ID, value between 1 and 7
+ * @return	0 on success, non-0 on failure
+ */
+int tps65090_fet_disable(unsigned int fet_id);
+
+/**
+ * Is FET enabled?
+ *
+ * @param	fet_id	FET ID, value between 1 and 7
+ * @return	1 enabled, 0 disabled, negative value on failure
+ */
+int tps65090_fet_is_enabled(unsigned int fet_id);
+
+/**
+ * Enable / disable the battery charger
+ *
+ * @param enable	0 to disable charging, non-zero to enable
+ */
+int tps65090_set_charge_enable(int enable);
+
+/**
+ * Check whether we have enabled battery charging
+ *
+ * @return 1 if enabled, 0 if disabled
+ */
+int tps65090_get_charging(void);
+
+/**
+ * Return the value of the status register
+ *
+ * @return status register value, or -1 on error
+ */
+int tps65090_get_status(void);
+
+/**
+ * Initialize the TPS65090 PMU.
+ *
+ * @return	0 on success, non-0 on failure
+ */
+int tps65090_init(void);
+
+#endif /* __TPS65090_H_ */



More information about the coreboot-gerrit mailing list