diff options
author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2014-06-02 08:43:48 +0200 |
---|---|---|
committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2014-06-02 08:43:48 +0200 |
commit | cc49da249cf2f380d2fed5571fad65ce6494fc95 (patch) | |
tree | 00bf437b6a370c0640d5fafd93780406d3531ebb /drivers | |
parent | 9637a1bb896efe392a58dd2772e2c3fcb646409d (diff) | |
parent | 567802bbd6bf1c809d37fef9244fc8a692244e73 (diff) | |
download | u-boot-imx-cc49da249cf2f380d2fed5571fad65ce6494fc95.zip u-boot-imx-cc49da249cf2f380d2fed5571fad65ce6494fc95.tar.gz u-boot-imx-cc49da249cf2f380d2fed5571fad65ce6494fc95.tar.bz2 |
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/dw_mmc.c | 12 | ||||
-rw-r--r-- | drivers/mmc/exynos_dw_mmc.c | 205 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 16 | ||||
-rw-r--r-- | drivers/mmc/s5p_sdhci.c | 42 | ||||
-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 | 1 | ||||
-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/power_fsl.c | 6 | ||||
-rw-r--r-- | drivers/power/power_i2c.c | 4 |
12 files changed, 495 insertions, 111 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index eb4e2be..5bf36a0 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -284,8 +284,8 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) static void dwmci_set_ios(struct mmc *mmc) { - struct dwmci_host *host = mmc->priv; - u32 ctype; + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 ctype, regs; debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); @@ -304,6 +304,14 @@ static void dwmci_set_ios(struct mmc *mmc) dwmci_writel(host, DWMCI_CTYPE, ctype); + regs = dwmci_readl(host, DWMCI_UHS_REG); + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + regs |= DWMCI_DDR_MODE; + else + regs &= DWMCI_DDR_MODE; + + dwmci_writel(host, DWMCI_UHS_REG, regs); + if (host->clksel) host->clksel(host); } diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index de8cdcc..d96dfe1 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -13,6 +13,8 @@ #include <asm/arch/dwmmc.h> #include <asm/arch/clk.h> #include <asm/arch/pinmux.h> +#include <asm/gpio.h> +#include <asm-generic/errno.h> #define DWMMC_MAX_CH_NUM 4 #define DWMMC_MAX_FREQ 52000000 @@ -44,7 +46,11 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host) & DWMCI_DIVRATIO_MASK) + 1; sclk = get_mmc_clk(host->dev_index); - return sclk / clk_div; + /* + * Assume to know divider value. + * When clock unit is broken, need to set "host->div" + */ + return sclk / clk_div / (host->div + 1); } static void exynos_dwmci_board_init(struct dwmci_host *host) @@ -60,48 +66,36 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) } } -/* - * This function adds the mmc channel to be registered with mmc core. - * index - mmc channel number. - * regbase - register base address of mmc channel specified in 'index'. - * bus_width - operating bus width of mmc channel specified in 'index'. - * clksel - value to be written into CLKSEL register in case of FDT. - * NULL in case od non-FDT. - */ -int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +static int exynos_dwmci_core_init(struct dwmci_host *host, int index) { - struct dwmci_host *host = NULL; unsigned int div; unsigned long freq, sclk; - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - printf("dwmci_host malloc fail!\n"); - return 1; - } + + if (host->bus_hz) + freq = host->bus_hz; + else + freq = DWMMC_MAX_FREQ; + /* request mmc clock vlaue of 52MHz. */ - freq = 52000000; sclk = get_mmc_clk(index); div = DIV_ROUND_UP(sclk, freq); /* set the clock divisor for mmc */ set_mmc_clk(index, div); host->name = "EXYNOS DWMMC"; - host->ioaddr = (void *)regbase; - host->buswidth = bus_width; #ifdef CONFIG_EXYNOS5420 host->quirks = DWMCI_QUIRK_DISABLE_SMU; #endif host->board_init = exynos_dwmci_board_init; - if (clksel) { - host->clksel_val = clksel; - } else { - if (0 == index) + if (!host->clksel_val) { + if (index == 0) host->clksel_val = DWMMC_MMC0_CLKSEL_VAL; - if (2 == index) + else if (index == 2) host->clksel_val = DWMMC_MMC2_CLKSEL_VAL; } + host->caps = MMC_MODE_DDR_52MHz; host->clksel = exynos_dwmci_clksel; host->dev_index = index; host->get_mmc_clk = exynos_dwmci_get_clk; @@ -113,69 +107,134 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) return 0; } +/* + * This function adds the mmc channel to be registered with mmc core. + * index - mmc channel number. + * regbase - register base address of mmc channel specified in 'index'. + * bus_width - operating bus width of mmc channel specified in 'index'. + * clksel - value to be written into CLKSEL register in case of FDT. + * NULL in case od non-FDT. + */ +int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +{ + struct dwmci_host *host = NULL; + + host = malloc(sizeof(struct dwmci_host)); + if (!host) { + error("dwmci_host malloc fail!\n"); + return -ENOMEM; + } + + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + + if (clksel) + host->clksel_val = clksel; + + return exynos_dwmci_core_init(host, index); +} + #ifdef CONFIG_OF_CONTROL -int exynos_dwmmc_init(const void *blob) +static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM]; + +static int do_dwmci_init(struct dwmci_host *host) { - int index, bus_width; - int node_list[DWMMC_MAX_CH_NUM]; - int err = 0, dev_id, flag, count, i; - u32 clksel_val, base, timing[3]; + int index, flag, err; - count = fdtdec_find_aliases_for_id(blob, "mmc", - COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list, - DWMMC_MAX_CH_NUM); + index = host->dev_index; - for (i = 0; i < count; i++) { - int node = node_list[i]; + flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; + err = exynos_pinmux_config(host->dev_id, flag); + if (err) { + debug("DWMMC not configure\n"); + return err; + } - if (node <= 0) - continue; + return exynos_dwmci_core_init(host, index); +} - /* Extract device id for each mmc channel */ - dev_id = pinmux_decode_periph_id(blob, node); +static int exynos_dwmci_get_config(const void *blob, int node, + struct dwmci_host *host) +{ + int err = 0; + u32 base, clksel_val, timing[3]; - /* Get the bus width from the device node */ - bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); - if (bus_width <= 0) { - debug("DWMMC: Can't get bus-width\n"); - return -1; - } - if (8 == bus_width) - flag = PINMUX_FLAG_8BIT_MODE; - else - flag = PINMUX_FLAG_NONE; + /* Extract device id for each mmc channel */ + host->dev_id = pinmux_decode_periph_id(blob, node); - /* config pinmux for each mmc channel */ - err = exynos_pinmux_config(dev_id, flag); - if (err) { - debug("DWMMC not configured\n"); - return err; - } + /* Get the bus width from the device node */ + host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0); + if (host->buswidth <= 0) { + debug("DWMMC: Can't get bus-width\n"); + return -EINVAL; + } - index = dev_id - PERIPH_ID_SDMMC0; + host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id); + if (host->dev_index == host->dev_id) + host->dev_index = host->dev_id - PERIPH_ID_SDMMC0; - /* Get the base address from the device node */ - base = fdtdec_get_addr(blob, node, "reg"); - if (!base) { - debug("DWMMC: Can't get base address\n"); - return -1; - } - /* Extract the timing info from the node */ - err = fdtdec_get_int_array(blob, node, "samsung,timing", - timing, 3); + /* Set the base address from the device node */ + base = fdtdec_get_addr(blob, node, "reg"); + if (!base) { + debug("DWMMC: Can't get base address\n"); + return -EINVAL; + } + host->ioaddr = (void *)base; + + /* Extract the timing info from the node */ + err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3); + if (err) { + debug("Can't get sdr-timings for devider\n"); + return -EINVAL; + } + + clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | + DWMCI_SET_DRV_CLK(timing[1]) | + DWMCI_SET_DIV_RATIO(timing[2])); + if (clksel_val) + host->clksel_val = clksel_val; + + host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0); + host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0); + host->div = fdtdec_get_int(blob, node, "div", 0); + + return 0; +} + +static int exynos_dwmci_process_node(const void *blob, + int node_list[], int count) +{ + struct dwmci_host *host; + int i, node, err; + + for (i = 0; i < count; i++) { + node = node_list[i]; + if (node <= 0) + continue; + host = &dwmci_host[i]; + err = exynos_dwmci_get_config(blob, node, host); if (err) { - debug("Can't get sdr-timings for divider\n"); - return -1; + debug("%s: failed to decode dev %d\n", __func__, i); + return err; } - clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | - DWMCI_SET_DRV_CLK(timing[1]) | - DWMCI_SET_DIV_RATIO(timing[2])); - /* Initialise each mmc channel */ - err = exynos_dwmci_add_port(index, base, bus_width, clksel_val); - if (err) - debug("dwmmc Channel-%d init failed\n", index); + do_dwmci_init(host); } return 0; } + +int exynos_dwmmc_init(const void *blob) +{ + int compat_id; + int node_list[DWMMC_MAX_CH_NUM]; + int err = 0, count; + + compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC; + + count = fdtdec_find_aliases_for_id(blob, "mmc", + compat_id, node_list, DWMMC_MAX_CH_NUM); + err = exynos_dwmci_process_node(blob, node_list, count); + + return err; +} #endif diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 8b53ead..55c2c68 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -160,6 +160,9 @@ int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + return 0; + cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = len; @@ -516,10 +519,13 @@ static int mmc_change_freq(struct mmc *mmc) return 0; /* High Speed is set, there are two types: 52MHz and 26MHz */ - if (cardtype & MMC_HS_52MHZ) + if (cardtype & EXT_CSD_CARD_TYPE_52) { + if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) + mmc->card_caps |= MMC_MODE_DDR_52MHz; mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - else + } else { mmc->card_caps |= MMC_MODE_HS; + } return 0; } @@ -1082,6 +1088,8 @@ static int mmc_startup(struct mmc *mmc) /* An array of possible bus widths in order of preference */ static unsigned ext_csd_bits[] = { + EXT_CSD_DDR_BUS_WIDTH_8, + EXT_CSD_DDR_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_8, EXT_CSD_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_1, @@ -1089,13 +1097,15 @@ static int mmc_startup(struct mmc *mmc) /* An array to map CSD bus widths to host cap bits */ static unsigned ext_to_hostcaps[] = { + [EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz, + [EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz, [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, }; /* An array to map chosen bus width to an integer */ static unsigned widths[] = { - 8, 4, 1, + 8, 4, 8, 4, 1, }; for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index ccae4cc..2ff0ec2 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -65,17 +65,9 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host) sdhci_writel(host, ctrl, SDHCI_CONTROL2); } -int s5p_sdhci_init(u32 regbase, int index, int bus_width) +static int s5p_sdhci_core_init(struct sdhci_host *host) { - struct sdhci_host *host = NULL; - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("sdhci__host malloc fail!\n"); - return 1; - } - host->name = S5P_NAME; - host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | @@ -85,15 +77,28 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width) host->set_control_reg = &s5p_sdhci_set_control_reg; host->set_clock = set_mmc_clk; - host->index = index; host->host_caps = MMC_MODE_HC; - if (bus_width == 8) + if (host->bus_width == 8) host->host_caps |= MMC_MODE_8BIT; return add_sdhci(host, 52000000, 400000); } +int s5p_sdhci_init(u32 regbase, int index, int bus_width) +{ + struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("sdhci__host malloc fail!\n"); + return 1; + } + host->ioaddr = (void *)regbase; + host->index = index; + host->bus_width = bus_width; + + return s5p_sdhci_core_init(host); +} + #ifdef CONFIG_OF_CONTROL struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; @@ -126,20 +131,7 @@ static int do_sdhci_init(struct sdhci_host *host) } } - host->name = S5P_NAME; - - host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | - SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_WAIT_SEND_CMD; - host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - - host->set_control_reg = &s5p_sdhci_set_control_reg; - host->set_clock = set_mmc_clk; - - host->host_caps = MMC_MODE_HC; - - return add_sdhci(host, 52000000, 400000); + return s5p_sdhci_core_init(host); } static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) 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..9a8bfe0 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,5 +11,6 @@ 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_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/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; |