diff --git a/src/drivers/ti/tps65090/tps65090.c b/src/drivers/ti/tps65090/tps65090.c index 60b8ec89f6..653d20da24 100644 --- a/src/drivers/ti/tps65090/tps65090.c +++ b/src/drivers/ti/tps65090/tps65090.c @@ -1,31 +1,48 @@ /* - * 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. + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * 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 -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; +#include +#include +#include +#include +#include "tps65090.h" /* 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 { @@ -42,125 +59,53 @@ enum { 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) +static int tps65090_i2c_write(unsigned int bus, + 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); + ret = i2c_write(bus, TPS65090_I2C_ADDR, reg_addr, 1, &value, 1); + printk(BIOS_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) +static int tps65090_i2c_read(unsigned int bus, + 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); + printk(BIOS_DEBUG, "%s: reg=%#x, ", __func__, reg_addr); + ret = i2c_read(bus, TPS65090_I2C_ADDR, reg_addr, 1, value, 1); if (ret) - debug("fail, ret=%d\n", ret); + printk(BIOS_DEBUG, "fail, ret=%d\n", ret); else - debug("value=%#x, ret=%d\n", *value, ret); + printk(BIOS_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 + * @fet_id Fet number to set (1..MAX_FET_NUM) + * @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) +static int tps65090_fet_set(unsigned int bus, enum fet_id fet_id, int set) { int retry, value; - uchar reg; + uint8_t 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)) + if (tps65090_i2c_write(bus, fet_id, 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, ®)) + if (tps65090_i2c_read(bus, fet_id, ®)) return FET_ERR_COMMS; /* Check that the fet went into the expected state */ @@ -171,27 +116,25 @@ static int tps65090_fet_set(int fet_id, int set) if (reg & FET_CTRL_TOFET) break; - mdelay(1); + udelay(1000); } - debug("FET %d: Power good should have set to %d but reg=%#02x\n", - fet_id, set, reg); + printk(BIOS_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) +/* FIXME(dhendrix): add timer API */ +#if 0 +int tps65090_fet_enable(unsigned int bus, enum fet_id fet_id) { int loops; - ulong start; + unsigned long 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); + ret = tps65090_fet_set(bus, fet_id, 1); if (!ret) break; @@ -199,16 +142,51 @@ int tps65090_fet_enable(unsigned int fet_id) break; /* Turn it off and try again until we time out */ - tps65090_fet_set(fet_id, 0); + tps65090_fet_set(bus, 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); + printk(BIOS_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); + printk(BIOS_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; +} +#endif +int tps65090_fet_enable(unsigned int bus, enum fet_id fet_id) +{ + int loops; + int ret = 0; + + for (loops = 0; loops < 100; loops++) { + ret = tps65090_fet_set(bus, fet_id, 1); + if (!ret) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(bus, fet_id, 0); + udelay(1000); + } + + if (ret) { + printk(BIOS_DEBUG, "%s: FET%d failed to power on\n", + __func__, fet_id); + } else if (loops) { + printk(BIOS_DEBUG, "%s: FET%d powered on\n", + __func__, fet_id); } /* * Unfortunately, there are some conditions where the power @@ -222,136 +200,63 @@ int tps65090_fet_enable(unsigned int fet_id) return ret; } -int tps65090_fet_disable(unsigned int fet_id) +int tps65090_fet_disable(unsigned int bus, enum fet_id 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; + return tps65090_fet_set(bus, fet_id, 0); } -int tps65090_fet_is_enabled(unsigned int fet_id) +int tps65090_fet_is_enabled(unsigned int bus, enum fet_id 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, ®); - tps65090_deselect(); + ret = tps65090_i2c_read(bus, fet_id, ®); if (ret) { - debug("fail to read FET%u_CTRL register over I2C", fet_id); + printk(BIOS_DEBUG, "fail to read FET%u_CTRL", fet_id); return -2; } return reg & FET_CTRL_ENFET; } -int tps65090_get_charging(void) +int tps65090_is_charging(unsigned int bus) { unsigned char val; int ret; - if (tps65090_select()) - return -1; - ret = tps65090_i2c_read(REG_CG_CTRL0, &val); - tps65090_deselect(); + ret = tps65090_i2c_read(bus, REG_CG_CTRL0, &val); if (ret) return ret; return val & CG_CTRL0_ENC_MASK ? 1 : 0; } -int tps65090_set_charge_enable(int enable) +int tps65090_set_charge_enable(unsigned int bus, int enable) { unsigned char val; int ret; - if (tps65090_select()) - return -1; - ret = tps65090_i2c_read(REG_CG_CTRL0, &val); + ret = tps65090_i2c_read(bus, 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); + ret = tps65090_i2c_write(bus, REG_CG_CTRL0, val); } - tps65090_deselect(); if (ret) { - debug("%s: Failed to read/write register\n", __func__); + printk(BIOS_DEBUG, "%s: Failed to enable\n", __func__); return ret; } return 0; } -int tps65090_get_status(void) +int tps65090_get_status(unsigned int bus) { unsigned char val; int ret; - if (tps65090_select()) - return -1; - ret = tps65090_i2c_read(REG_CG_STATUS1, &val); - tps65090_deselect(); + ret = tps65090_i2c_read(bus, REG_CG_STATUS1, &val); 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 index b008a55635..b38db59892 100644 --- a/src/drivers/ti/tps65090/tps65090.h +++ b/src/drivers/ti/tps65090/tps65090.h @@ -1,7 +1,32 @@ /* - * 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. + * Copyright 2012, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free @@ -14,6 +39,17 @@ /* I2C device address for TPS65090 PMU */ #define TPS65090_I2C_ADDR 0x48 +/* TPS65090 FET control registers */ +enum fet_id { + FET1_CTRL = 0x0f, + FET2_CTRL, + FET3_CTRL, + FET4_CTRL, + FET5_CTRL, + FET6_CTRL, + FET7_CTRL, +}; + enum { /* Status register fields */ TPS65090_ST1_OTC = 1 << 0, @@ -31,53 +67,52 @@ enum { /** * Enable FET * - * @param fet_id FET ID, value between 1 and 7 - * @return 0 on success, non-0 on failure + * @bus I2C bus number the TPS65090 is on + * @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); +int tps65090_fet_enable(unsigned int bus, enum fet_id fet_id); /** * Disable FET * - * @param fet_id FET ID, value between 1 and 7 + * @bus I2C bus number the TPS65090 is on + * @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); +int tps65090_fet_disable(unsigned int bus, enum fet_id fet_id); /** * Is FET enabled? * - * @param fet_id FET ID, value between 1 and 7 + * @bus I2C bus number the TPS65090 is on + * @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); +int tps65090_fet_is_enabled(unsigned int bus, enum fet_id fet_id); /** * Enable / disable the battery charger * - * @param enable 0 to disable charging, non-zero to enable + * @bus I2C bus number the TPS65090 is on + * @enable 0 to disable charging, non-zero to enable */ -int tps65090_set_charge_enable(int enable); +int tps65090_set_charge_enable(unsigned int bus, int enable); /** * Check whether we have enabled battery charging * + * @bus I2C bus number the TPS65090 is on * @return 1 if enabled, 0 if disabled */ -int tps65090_get_charging(void); +int tps65090_is_charging(unsigned int bus); /** * Return the value of the status register * + * @bus I2C bus number the TPS65090 is on * @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); +int tps65090_get_status(unsigned int bus); #endif /* __TPS65090_H_ */