summaryrefslogtreecommitdiff
path: root/drivers/power/tps6586x.c
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2012-05-20 21:31:26 +0200
committerWolfgang Denk <wd@denx.de>2012-05-20 21:31:26 +0200
commitee3a55fdf00b54391e406217e53674449e70d78b (patch)
tree0c7edb3ba668e5a215c42e8b1429cc3f394351b2 /drivers/power/tps6586x.c
parent6bc337fb13003a9a949dfb2713e308fb97faae8a (diff)
parent2ca4a209a5b961ad1be8782c68dabe326d77dfaf (diff)
downloadolio-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.c280
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;
+}