diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/battery/bat_trats.c | 4 | ||||
-rw-r--r-- | drivers/power/battery/bat_trats2.c | 2 | ||||
-rw-r--r-- | drivers/power/mfd/pmic_max77693.c | 2 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_max8997.c | 2 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_tps65090.c | 310 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_tps65218.c | 97 | ||||
-rw-r--r-- | drivers/power/power_fsl.c | 6 | ||||
-rw-r--r-- | drivers/power/power_i2c.c | 4 |
9 files changed, 421 insertions, 8 deletions
diff --git a/drivers/power/battery/bat_trats.c b/drivers/power/battery/bat_trats.c index 41b179f..bfde692 100644 --- a/drivers/power/battery/bat_trats.c +++ b/drivers/power/battery/bat_trats.c @@ -19,7 +19,7 @@ static int power_battery_charge(struct pmic *bat) struct battery *battery = p_bat->bat; int k; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) && @@ -42,7 +42,7 @@ static int power_battery_charge(struct pmic *bat) } } exit: - bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0); + bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_DISABLE, 0); return 0; } diff --git a/drivers/power/battery/bat_trats2.c b/drivers/power/battery/bat_trats2.c index 94015aa..57221ad 100644 --- a/drivers/power/battery/bat_trats2.c +++ b/drivers/power/battery/bat_trats2.c @@ -17,7 +17,7 @@ static int power_battery_charge(struct pmic *bat) { struct power_battery *p_bat = bat->pbat; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; return 0; diff --git a/drivers/power/mfd/pmic_max77693.c b/drivers/power/mfd/pmic_max77693.c index 1a4416b..6b28e28 100644 --- a/drivers/power/mfd/pmic_max77693.c +++ b/drivers/power/mfd/pmic_max77693.c @@ -22,7 +22,7 @@ static int max77693_charger_state(struct pmic *p, int state, int current) val = MAX77693_CHG_UNLOCK; pmic_reg_write(p, MAX77693_CHG_CNFG_06, val); - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val); val &= ~0x01; diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 920bbdc..a472f61 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,5 +11,7 @@ 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_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_max8997.c b/drivers/power/pmic/pmic_max8997.c index ba01692..a36a9a0 100644 --- a/drivers/power/pmic/pmic_max8997.c +++ b/drivers/power/pmic/pmic_max8997.c @@ -35,7 +35,7 @@ static int pmic_charger_state(struct pmic *p, int state, int current) if (pmic_probe(p)) return -1; - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val); val &= ~(MBCHOSTEN | VCHGR_FC); diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..c5b3966 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TPS65090_NAME "TPS65090_PMIC" + +/* TPS65090 register addresses */ +enum { + REG_IRQ1 = 0, + 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, + TPS65090_NUM_REGS, +}; + +enum { + IRQ1_VBATG = 1 << 3, + 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 */ +}; + +/** + * Checks for a valid FET number + * + * @param fet_id FET number to check + * @return 0 if ok, -EINVAL 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 -EINVAL; + } + + return 0; +} + +/** + * Set the power state for a FET + * + * @param pmic pmic structure for the tps65090 + * @param fet_id Fet number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{ + int retry; + u32 reg, value; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®)) + return -EIO; + + /* 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 -EAGAIN; +} + +int tps65090_fet_enable(unsigned int fet_id) +{ + struct pmic *pmic; + ulong start; + int loops; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(pmic, fet_id, true); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(pmic, fet_id, false); + } + + 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 == -EAGAIN) + ret = 0; + + return ret; +} + +int tps65090_fet_disable(unsigned int fet_id) +{ + struct pmic *pmic; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + ret = tps65090_fet_set(pmic, fet_id, false); + + return ret; +} + +int tps65090_fet_is_enabled(unsigned int fet_id) +{ + struct pmic *pmic; + u32 reg; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -ENODEV; + ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®); + if (ret) { + debug("fail to read FET%u_CTRL register over I2C", fet_id); + return -EIO; + } + + return reg & FET_CTRL_ENFET; +} + +int tps65090_get_charging(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (ret) + return ret; + + return !!(val & CG_CTRL0_ENC_MASK); +} + +static int tps65090_charger_state(struct pmic *pmic, int state, + int current) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (!ret) { + if (state == PMIC_CHARGER_ENABLE) + val |= CG_CTRL0_ENC_MASK; + else + val &= ~CG_CTRL0_ENC_MASK; + ret = pmic_reg_write(pmic, REG_CG_CTRL0, val); + } + if (ret) { + debug("%s: Failed to read/write register\n", __func__); + return ret; + } + + return 0; +} + +int tps65090_get_status(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val); + if (ret) + return ret; + + return val; +} + +static int tps65090_charger_bat_present(struct pmic *pmic) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_IRQ1, &val); + if (ret) + return ret; + + return !!(val & IRQ1_VBATG); +} + +static struct power_chrg power_chrg_pmic_ops = { + .chrg_bat_present = tps65090_charger_bat_present, + .chrg_state = tps65090_charger_state, +}; + +int tps65090_init(void) +{ + struct pmic *p; + int bus; + int addr; + const void *blob = gd->fdt_blob; + int node, parent; + + node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090); + if (node < 0) { + debug("PMIC: No node for PMIC Chip in device tree\n"); + debug("node = %d\n", node); + return -ENODEV; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -EINVAL; + } + + bus = i2c_get_bus_num_fdt(parent); + if (p->bus < 0) { + debug("%s: Cannot find I2C bus\n", __func__); + return -ENOENT; + } + addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR); + p = pmic_alloc(); + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = TPS65090_NAME; + p->bus = bus; + p->interface = PMIC_I2C; + p->number_of_regs = TPS65090_NUM_REGS; + p->hw.i2c.addr = addr; + p->hw.i2c.tx_num = 1; + p->chrg = &power_chrg_pmic_ops; + + puts("TPS65090 PMIC init\n"); + + return 0; +} diff --git a/drivers/power/pmic/pmic_tps65218.c b/drivers/power/pmic/pmic_tps65218.c new file mode 100644 index 0000000..0952456 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65218.c @@ -0,0 +1,97 @@ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <power/tps65218.h> + +/** + * tps65218_reg_write() - Generic function that can write a TPS65218 PMIC + * register or bit field regardless of protection + * level. + * + * @prot_level: Register password protection. Use + * TPS65218_PROT_LEVEL_NONE, + * TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2 + * @dest_reg: Register address to write. + * @dest_val: Value to write. + * @mask: Bit mask (8 bits) to be applied. Function will only + * change bits that are set in the bit mask. + * + * @return: 0 for success, not 0 on failure, as per the i2c API + */ +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1); + if (ret) + return ret; + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK; + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + } + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} + +/** + * tps65218_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @dc_cntrl_reg: DC voltage control register to change. + * @volt_sel: New value for the voltage register + * @return: 0 for success, not 0 on failure. + */ +int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) +{ + if ((dc_cntrl_reg != TPS65218_DCDC1) && + (dc_cntrl_reg != TPS65218_DCDC2)) + return 1; + + /* set voltage level */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel, + TPS65218_MASK_ALL_BITS)) + return 1; + + /* set GO bit to initiate voltage transition */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW, + TPS65218_DCDC_GO, TPS65218_DCDC_GO)) + return 1; + + return 0; +} diff --git a/drivers/power/power_fsl.c b/drivers/power/power_fsl.c index ac0b541..a64161b 100644 --- a/drivers/power/power_fsl.c +++ b/drivers/power/power_fsl.c @@ -11,9 +11,9 @@ #include <fsl_pmic.h> #include <errno.h> -#if defined(CONFIG_PMIC_FSL_MC13892) +#if defined(CONFIG_POWER_FSL_MC13892) #define FSL_PMIC_I2C_LENGTH 3 -#elif defined(CONFIG_PMIC_FSL_MC34704) +#elif defined(CONFIG_POWER_FSL_MC34704) #define FSL_PMIC_I2C_LENGTH 1 #endif @@ -51,7 +51,7 @@ int pmic_init(unsigned char bus) p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR; p->hw.i2c.tx_num = FSL_PMIC_I2C_LENGTH; #else -#error "You must select CONFIG_POWER_SPI or CONFIG_PMIC_I2C" +#error "You must select CONFIG_POWER_SPI or CONFIG_POWER_I2C" #endif return 0; diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c index ac76870..594cd11 100644 --- a/drivers/power/power_i2c.c +++ b/drivers/power/power_i2c.c @@ -23,6 +23,8 @@ int pmic_reg_write(struct pmic *p, u32 reg, u32 val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + switch (pmic_i2c_tx_num) { case 3: if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { @@ -66,6 +68,8 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) return -1; |