diff options
| author | Wolfgang Denk <wd@denx.de> | 2012-05-20 21:31:26 +0200 |
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2012-05-20 21:31:26 +0200 |
| commit | ee3a55fdf00b54391e406217e53674449e70d78b (patch) | |
| tree | 0c7edb3ba668e5a215c42e8b1429cc3f394351b2 /drivers/power/tps6586x.c | |
| parent | 6bc337fb13003a9a949dfb2713e308fb97faae8a (diff) | |
| parent | 2ca4a209a5b961ad1be8782c68dabe326d77dfaf (diff) | |
| download | olio-uboot-2014.01-ee3a55fdf00b54391e406217e53674449e70d78b.tar.xz olio-uboot-2014.01-ee3a55fdf00b54391e406217e53674449e70d78b.zip | |
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm: (167 commits)
OMAP4/5: Change omap4_sdp, omap4_panda, omap5_evm maintainer
ARM: omap3: Add CONFIG_SPL_BOARD_INIT for CONFIG_SPL_MMC_SUPPORT
ARM: omap3: Set SPL stack size to 8KB, image to 54KB.
arm, omap3: fix warm reset serial output on OMAP36xx/AM/DM37xx
OMAP4: Set fdt_high for OMAP4 devices to enable booting with Device Tree
omap4: do not enable auxiliary cores
omap4: do not enable fs-usb module
omap4: panda: disable uart2 pads during boot
igep00x0: change mpurate from 500 to auto
igep00x0: enable the use of a plain text file
tegra2: trivially enable 13 mhz crystal frequency
tegra: Enable keyboard for Seaboard
tegra: Switch on console mux and use environment for console
tegra: Add tegra keyboard driver
tegra: fdt: Add keyboard definitions for Seaboard
tegra: fdt: Add keyboard controller definition
tegra: Add keyboard support to funcmux
input: Add support for keyboard matrix decoding from an fdt
input: Add generic keyboard input handler
input: Add linux/input.h for key code support
fdt: Add fdtdec functions to read byte array
tegra: Enable LP0 on Seaboard
tegra: fdt: Add EMC data for Tegra2 Seaboard
tegra: i2c: Add function to find DVC bus
fdt: tegra: Add EMC node to device tree
tegra: Add EMC settings for Seaboard
tegra: Turn off power detect in board init
tegra: Set up warmboot code on Nvidia boards
tegra: Setup PMC scratch info from ap20 setup
tegra: Add warmboot implementation
tegra: Set up PMU for Nvidia boards
tegra: Add PMU to manage power supplies
tegra: Add EMC support for optimal memory timings
tegra: Add header file for APB_MISC register
tegra: Add tegra_get_chip_type() to detect SKU
tegra: Add flow, gp_padctl, fuse, sdram headers
tegra: Add crypto library for warmboot code
tegra: Add functions to access low-level Osc/PLL details
tegra: Move ap20.h header into arch location
Add AES crypto library
i2c: Add TPS6586X driver
Add abs() macro to return absolute value
fdt: Add function to return next compatible subnode
fdt: Add function to locate an array in the device tree
i.MX28: Avoid redefining serial_put[cs]()
i.MX28: Check if WP detection is implemented at all
i.MX28: Add battery boot components to SPL
i.MX28: Reorder battery status functions in SPL
i.MX28: Add LRADC init to i.MX28 SPL
i.MX28: Add LRADC register definitions
i.MX28: Shut down the LCD controller before reset
i.MX28: Add LCDIF register definitions
i.MX28: Implement boot pads sampling and reporting
i.MX28: Improve passing of data from SPL to U-Boot
M28EVK: Add SD update command
M28EVK: Implement support for new board V2.0
FEC: Abstract out register setup
MX5: PAD_CTL_DRV_VOT_LOW and PAD_CTL_DRV_VOT_HIGH exchanged
i.MX28: Add delay after CPU bypass is cleared
spi: mxs: Allow other chip selects to work
spi: mxs: Introduce spi_cs_is_valid()
mx53loco: Remove unneeded gpio_set_value()
mx53loco: Add CONFIG_REVISION_TAG
mx53loco: Turn on VUSB regulator
mx53loco: Add mc34708 support and set mx53 frequency at 1GHz
pmic: dialog: Avoid name conflicts
imx: Add u-boot.imx as target for ARM9 i.MX SOCs
i.MX2: Include asm/types.h in arch-mx25/imx-regs.h
imx: usb: There is no such register
i.MX25: usb: Set PORTSCx register
imx: nand: Support flash based BBT
i.MX25: This architecture has a GPIO4 too
i.MX25: esdhc: Add mxc_get_clock infrastructure
i.MX6: mx6q_sabrelite: add SATA bindings
i.MX6: add enable_sata_clock()
i.MX6: Add ANATOP regulator init
mx28evk: add NAND support
USB: ehci-mx6: Fix broken IO access
M28: Scan only first 512 MB of DRAM to avoid memory wraparound
Revert "i.MX28: Enable additional DRAM address bits"
M28: Enable FDT support
mx53loco: Add support for 1GHz operation for DA9053-based boards
mx53loco: Allow to print CPU information at a later stage
mx5: Add clock config interface
imx-common: Factor out get_ahb_clk()
i.MX6Q: mx6qsabrelite: Add keypress support to alter boot flow
mx31pdk: Allow booting a zImage kernel
mx6qarm2: Allow booting a zImage kernel
mx6qsabrelite: Allow booting a zImage kernel
mx28evk: Allow booting a zImage kernel
m28evk: Allow to booting a dt kernel
mx28evk: Allow to booting a dt kernel
mx6qsabrelite: No need to set the direction for GPIO3_23 again
pmic: Add support for the Dialog DA9053 PMIC
MX53: mx53loco: Add SATA support
MX53: Add support to ESG ima3 board
SATA: add driver for MX5 / MX6 SOCs
MX53: add function to set SATA clock to internal
SATA: check for return value from sata functions
MX5: Add definitions for SATA controller
NET: fec_mxc.c: Add a way to disable auto negotiation
Define UART4 and UART5 base addresses
EXYNOS: Change bits per pixel value proper for u-boot.
EXYNOS: support TRATS board display function
LCD: support S6E8AX0 amoled driver based on EXYNOS MIPI DSI
EXYNOS: support EXYNOS MIPI DSI interface driver.
EXYNOS: support EXYNOS framebuffer and FIMD display drivers.
LCD: add data structure for EXYNOS display driver
EXYNOS: add LCD and MIPI DSI clock interface.
EXYNOS: definitions of system resgister and power management registers.
SMDK5250: fix compiler warning
misc:pmic:samsung Convert TRATS target to use MAX8997 instead of MAX8998
misc:pmic:max8997 MAX8997 support for PMIC driver
TRATS: modify the trats's configuration
ARM: Exynos4: ADC: Universal_C210: Enable LDO4 power line for ADC measurement
EXYNOS: Rename exynos5_tzpc structure to exynos_tzpc
arm: ea20: Change macro from BOARD_LATE_INIT to CONFIG_BOARD_LATE_INIT
arm: cam_enc_4xx: Change macro from BOARD_LATE_INIT to CONFIG_BOARD_LATE_INIT
cm-t35: add I2C multi-bus support
include/configs: Remove CONFIG_SYS_64BIT_STRTOUL
include/configs: Remove CONFIG_SYS_64BIT_VSPRINTF
omap3: Introduce weak misc_init_r
omap730p2: Remove empty misc_init_r
omap5912osk: Remove empty misc_init_r
omap4+: Remove CONFIG_ARCH_CPU_INIT
omap4: Remove CONFIG_SYS_MMC_SET_DEV
OMAP3: pandora: drop console kernel argument
OMAP3: pandora: revise GPIO configuration
...
Diffstat (limited to 'drivers/power/tps6586x.c')
| -rw-r--r-- | drivers/power/tps6586x.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c new file mode 100644 index 000000000..f3f2ec6e5 --- /dev/null +++ b/drivers/power/tps6586x.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <i2c.h> + +static int bus_num; /* I2C bus we are on */ +#define I2C_ADDRESS 0x34 /* chip requires this address */ +static char inited; /* 1 if we have been inited */ + +enum { + /* Registers that we access */ + SUPPLY_CONTROL1 = 0x20, + SUPPLY_CONTROL2, + SM1_VOLTAGE_V1 = 0x23, + SM1_VOLTAGE_V2, + SM0_VOLTAGE_V1 = 0x26, + SM0_VOLTAGE_V2, + PFM_MODE = 0x47, + + /* Bits in the supply control registers */ + CTRL_SM1_RAMP = 0x01, + CTRL_SM1_SUPPLY2 = 0x02, + CTRL_SM0_RAMP = 0x04, + CTRL_SM0_SUPPLY2 = 0x08, +}; + +#define MAX_I2C_RETRY 3 +int tps6586x_read(int reg) +{ + int i; + uchar data; + int retval = -1; + int old_bus_num; + + old_bus_num = i2c_get_bus_num(); + i2c_set_bus_num(bus_num); + + for (i = 0; i < MAX_I2C_RETRY; ++i) { + if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) { + retval = (int)data; + goto exit; + } + + /* i2c access failed, retry */ + udelay(100); + } + +exit: + i2c_set_bus_num(old_bus_num); + debug("pmu_read %x=%x\n", reg, retval); + if (retval < 0) + debug("%s: failed to read register %#x: %d\n", __func__, reg, + retval); + return retval; +} + +int tps6586x_write(int reg, uchar *data, uint len) +{ + int i; + int retval = -1; + int old_bus_num; + + old_bus_num = i2c_get_bus_num(); + i2c_set_bus_num(bus_num); + + for (i = 0; i < MAX_I2C_RETRY; ++i) { + if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) { + retval = 0; + goto exit; + } + + /* i2c access failed, retry */ + udelay(100); + } + +exit: + i2c_set_bus_num(old_bus_num); + debug("pmu_write %x=%x: ", reg, retval); + for (i = 0; i < len; i++) + debug("%x ", data[i]); + if (retval) + debug("%s: failed to write register %#x\n", __func__, reg); + return retval; +} + +/* + * Get current voltage of SM0 and SM1 + * + * @param sm0 Place to put SM0 voltage + * @param sm1 Place to put SM1 voltage + * @return 0 if ok, -1 on error + */ +static int read_voltages(int *sm0, int *sm1) +{ + int ctrl1, ctrl2; + int is_v2; + + /* + * Each vdd has two supply sources, ie, v1 and v2. + * The supply control reg1 and reg2 determine the current selection. + */ + ctrl1 = tps6586x_read(SUPPLY_CONTROL1); + ctrl2 = tps6586x_read(SUPPLY_CONTROL2); + if (ctrl1 == -1 || ctrl2 == -1) + return -1; + + /* Figure out whether V1 or V2 is selected */ + is_v2 = (ctrl1 | ctrl2) & CTRL_SM0_SUPPLY2; + *sm0 = tps6586x_read(is_v2 ? SM0_VOLTAGE_V2 : SM0_VOLTAGE_V1); + *sm1 = tps6586x_read(is_v2 ? SM1_VOLTAGE_V2 : SM1_VOLTAGE_V1); + if (*sm0 == -1 || *sm1 == -1) + return -1; + + return 0; +} + +static int set_voltage(int reg, int data, int rate) +{ + uchar control_bit; + uchar buff[3]; + + control_bit = (reg == SM0_VOLTAGE_V1 ? CTRL_SM0_RAMP : CTRL_SM1_RAMP); + + /* + * Only one supply is needed in u-boot. set both v1 and v2 to + * same value. + * + * When both v1 and v2 are set to same value, we just need to set + * control1 reg to trigger the supply selection. + */ + buff[0] = buff[1] = (uchar)data; + buff[2] = rate; + + /* write v1, v2 and rate, then trigger */ + if (tps6586x_write(reg, buff, 3) || + tps6586x_write(SUPPLY_CONTROL1, &control_bit, 1)) + return -1; + + return 0; +} + +static int calculate_next_voltage(int voltage, int target, int step) +{ + int diff = voltage < target ? step : -step; + + if (abs(target - voltage) > step) + voltage += diff; + else + voltage = target; + + return voltage; +} + +int tps6586x_set_pwm_mode(int mask) +{ + uchar val; + int ret; + + assert(inited); + ret = tps6586x_read(PFM_MODE); + if (ret != -1) { + val = (uchar)ret; + val |= mask; + + ret = tps6586x_write(PFM_MODE, &val, 1); + } + + if (ret == -1) + debug("%s: Failed to read/write PWM mode reg\n", __func__); + + return ret; +} + +int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, + int min_sm0_over_sm1) +{ + int sm0, sm1; + int bad; + + assert(inited); + + /* get current voltage settings */ + if (read_voltages(&sm0, &sm1)) { + debug("%s: Cannot read voltage settings\n", __func__); + return -1; + } + + /* + * if vdd_core < vdd_cpu + rel + * skip + * + * This condition may happen when system reboots due to kernel crash. + */ + if (min_sm0_over_sm1 != -1 && sm0 < sm1 + min_sm0_over_sm1) { + debug("%s: SM0 is %d, SM1 is %d, but min_sm0_over_sm1 is %d\n", + __func__, sm0, sm1, min_sm0_over_sm1); + return -1; + } + + /* + * Since vdd_core and vdd_cpu may both stand at either greater or less + * than their nominal voltage, the adjustment may go either directions. + * + * Make sure vdd_core is always higher than vdd_cpu with certain margin. + * So, find out which vdd to adjust first in each step. + * + * case 1: both sm0 and sm1 need to move up + * adjust sm0 before sm1 + * + * case 2: both sm0 and sm1 need to move down + * adjust sm1 before sm0 + * + * case 3: sm0 moves down and sm1 moves up + * adjusting either one first is fine. + * + * Adjust vdd_core and vdd_cpu one step at a time until they reach + * their nominal values. + */ + bad = 0; + while (!bad && (sm0 != sm0_target || sm1 != sm1_target)) { + int adjust_sm0_late = 0; /* flag to adjust vdd_core later */ + + debug("%d-%d %d-%d ", sm0, sm0_target, sm1, sm1_target); + + if (sm0 != sm0_target) { + /* + * if case 1 and case 3, set new sm0 first. + * otherwise, hold down until new sm1 is set. + */ + sm0 = calculate_next_voltage(sm0, sm0_target, step); + if (sm1 < sm1_target) + bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate); + else + adjust_sm0_late = 1; + } + + if (sm1 != sm1_target) { + sm1 = calculate_next_voltage(sm1, sm1_target, step); + bad |= set_voltage(SM1_VOLTAGE_V1, sm1, rate); + } + + if (adjust_sm0_late) + bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate); + debug("%d\n", adjust_sm0_late); + } + debug("%d-%d %d-%d done\n", sm0, sm0_target, sm1, sm1_target); + + return bad ? -1 : 0; +} + +int tps6586x_init(int bus) +{ + bus_num = bus; + inited = 1; + + return 0; +} |