summaryrefslogtreecommitdiffstats
path: root/qemu/roms/u-boot/drivers/power
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/u-boot/drivers/power
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/drivers/power')
-rw-r--r--qemu/roms/u-boot/drivers/power/Makefile19
-rw-r--r--qemu/roms/u-boot/drivers/power/battery/Makefile9
-rw-r--r--qemu/roms/u-boot/drivers/power/battery/bat_trats.c89
-rw-r--r--qemu/roms/u-boot/drivers/power/battery/bat_trats2.c65
-rw-r--r--qemu/roms/u-boot/drivers/power/exynos-tmu.c346
-rw-r--r--qemu/roms/u-boot/drivers/power/ftpmu010.c88
-rw-r--r--qemu/roms/u-boot/drivers/power/fuel_gauge/Makefile8
-rw-r--r--qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c286
-rw-r--r--qemu/roms/u-boot/drivers/power/mfd/Makefile10
-rw-r--r--qemu/roms/u-boot/drivers/power/mfd/fg_max77693.c139
-rw-r--r--qemu/roms/u-boot/drivers/power/mfd/muic_max77693.c77
-rw-r--r--qemu/roms/u-boot/drivers/power/mfd/pmic_max77693.c96
-rw-r--r--qemu/roms/u-boot/drivers/power/palmas.c160
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/Makefile14
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/muic_max8997.c74
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_max77686.c255
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_max8997.c107
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_max8998.c33
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c32
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_tps65217.c109
-rw-r--r--qemu/roms/u-boot/drivers/power/pmic/pmic_tps65910.c83
-rw-r--r--qemu/roms/u-boot/drivers/power/power_core.c223
-rw-r--r--qemu/roms/u-boot/drivers/power/power_dialog.c32
-rw-r--r--qemu/roms/u-boot/drivers/power/power_fsl.c58
-rw-r--r--qemu/roms/u-boot/drivers/power/power_i2c.c109
-rw-r--r--qemu/roms/u-boot/drivers/power/power_spi.c92
-rw-r--r--qemu/roms/u-boot/drivers/power/tps6586x.c264
-rw-r--r--qemu/roms/u-boot/drivers/power/twl4030.c101
-rw-r--r--qemu/roms/u-boot/drivers/power/twl6030.c235
29 files changed, 3213 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/power/Makefile b/qemu/roms/u-boot/drivers/power/Makefile
new file mode 100644
index 000000000..53ff97d74
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2009 Wind River Systems, Inc.
+# Tom Rix <Tom.Rix at windriver.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
+obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o
+obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o
+obj-$(CONFIG_TWL4030_POWER) += twl4030.o
+obj-$(CONFIG_TWL6030_POWER) += twl6030.o
+obj-$(CONFIG_PALMAS_POWER) += palmas.o
+
+obj-$(CONFIG_POWER) += power_core.o
+obj-$(CONFIG_DIALOG_POWER) += power_dialog.o
+obj-$(CONFIG_POWER_FSL) += power_fsl.o
+obj-$(CONFIG_POWER_I2C) += power_i2c.o
+obj-$(CONFIG_POWER_SPI) += power_spi.o
diff --git a/qemu/roms/u-boot/drivers/power/battery/Makefile b/qemu/roms/u-boot/drivers/power/battery/Makefile
new file mode 100644
index 000000000..f864f0439
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/battery/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_POWER_BATTERY_TRATS) += bat_trats.o
+obj-$(CONFIG_POWER_BATTERY_TRATS2) += bat_trats2.o
diff --git a/qemu/roms/u-boot/drivers/power/battery/bat_trats.c b/qemu/roms/u-boot/drivers/power/battery/bat_trats.c
new file mode 100644
index 000000000..41b179fc5
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/battery/bat_trats.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/battery.h>
+#include <power/max8997_pmic.h>
+#include <errno.h>
+
+static struct battery battery_trats;
+
+static int power_battery_charge(struct pmic *bat)
+{
+ struct power_battery *p_bat = bat->pbat;
+ struct battery *battery = p_bat->bat;
+ int k;
+
+ if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450))
+ return -1;
+
+ for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) &&
+ bat->chrg->chrg_type(p_bat->muic) &&
+ battery->state_of_chrg < 100; k++) {
+ udelay(2000000);
+ if (!(k % 5))
+ puts(".");
+ bat->fg->fg_battery_update(p_bat->fg, bat);
+
+ if (k == 200) {
+ debug(" %d [V]", battery->voltage_uV);
+ puts("\n");
+ k = 0;
+ }
+
+ if (ctrlc()) {
+ printf("\nCharging disabled on request.\n");
+ goto exit;
+ }
+ }
+ exit:
+ bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0);
+
+ return 0;
+}
+
+static int power_battery_init_trats(struct pmic *bat_,
+ struct pmic *fg_,
+ struct pmic *chrg_,
+ struct pmic *muic_)
+{
+ bat_->pbat->fg = fg_;
+ bat_->pbat->chrg = chrg_;
+ bat_->pbat->muic = muic_;
+
+ bat_->fg = fg_->fg;
+ bat_->chrg = chrg_->chrg;
+ bat_->chrg->chrg_type = muic_->chrg->chrg_type;
+ return 0;
+}
+
+static struct power_battery power_bat_trats = {
+ .bat = &battery_trats,
+ .battery_init = power_battery_init_trats,
+ .battery_charge = power_battery_charge,
+};
+
+int power_bat_init(unsigned char bus)
+{
+ static const char name[] = "BAT_TRATS";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board BAT init\n");
+
+ p->interface = PMIC_NONE;
+ p->name = name;
+ p->bus = bus;
+
+ p->pbat = &power_bat_trats;
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/battery/bat_trats2.c b/qemu/roms/u-boot/drivers/power/battery/bat_trats2.c
new file mode 100644
index 000000000..94015aa41
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/battery/bat_trats2.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/battery.h>
+#include <power/max77693_pmic.h>
+#include <errno.h>
+
+static struct battery battery_trats;
+
+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))
+ return -1;
+
+ return 0;
+}
+
+static int power_battery_init_trats2(struct pmic *bat_,
+ struct pmic *fg_,
+ struct pmic *chrg_,
+ struct pmic *muic_)
+{
+ bat_->pbat->fg = fg_;
+ bat_->pbat->chrg = chrg_;
+ bat_->pbat->muic = muic_;
+
+ bat_->fg = fg_->fg;
+ bat_->chrg = chrg_->chrg;
+ bat_->chrg->chrg_type = muic_->chrg->chrg_type;
+ return 0;
+}
+
+static struct power_battery power_bat_trats2 = {
+ .bat = &battery_trats,
+ .battery_init = power_battery_init_trats2,
+ .battery_charge = power_battery_charge,
+};
+
+int power_bat_init(unsigned char bus)
+{
+ static const char name[] = "BAT_TRATS2";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board BAT init\n");
+
+ p->interface = PMIC_NONE;
+ p->name = name;
+ p->bus = bus;
+
+ p->pbat = &power_bat_trats2;
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/exynos-tmu.c b/qemu/roms/u-boot/drivers/power/exynos-tmu.c
new file mode 100644
index 000000000..9a093a5bd
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/exynos-tmu.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Akshay Saraswat <akshay.s@samsung.com>
+ *
+ * EXYNOS - Thermal Management Unit
+ *
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ * 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 <errno.h>
+#include <fdtdec.h>
+#include <tmu.h>
+#include <asm/arch/tmu.h>
+#include <asm/arch/power.h>
+
+#define TRIMINFO_RELOAD 1
+#define CORE_EN 1
+#define THERM_TRIP_EN (1 << 12)
+
+#define INTEN_RISE0 1
+#define INTEN_RISE1 (1 << 4)
+#define INTEN_RISE2 (1 << 8)
+#define INTEN_FALL0 (1 << 16)
+#define INTEN_FALL1 (1 << 20)
+#define INTEN_FALL2 (1 << 24)
+
+#define TRIM_INFO_MASK 0xff
+
+#define INTCLEAR_RISE0 1
+#define INTCLEAR_RISE1 (1 << 4)
+#define INTCLEAR_RISE2 (1 << 8)
+#define INTCLEAR_FALL0 (1 << 16)
+#define INTCLEAR_FALL1 (1 << 20)
+#define INTCLEAR_FALL2 (1 << 24)
+#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
+ INTCLEAR_RISE2 | INTCLEAR_FALL0 | \
+ INTCLEAR_FALL1 | INTCLEAR_FALL2)
+
+/* Tmeperature threshold values for various thermal events */
+struct temperature_params {
+ /* minimum value in temperature code range */
+ unsigned min_val;
+ /* maximum value in temperature code range */
+ unsigned max_val;
+ /* temperature threshold to start warning */
+ unsigned start_warning;
+ /* temperature threshold CPU tripping */
+ unsigned start_tripping;
+ /* temperature threshold for HW tripping */
+ unsigned hardware_tripping;
+};
+
+/* Pre-defined values and thresholds for calibration of current temperature */
+struct tmu_data {
+ /* pre-defined temperature thresholds */
+ struct temperature_params ts;
+ /* pre-defined efuse range minimum value */
+ unsigned efuse_min_value;
+ /* pre-defined efuse value for temperature calibration */
+ unsigned efuse_value;
+ /* pre-defined efuse range maximum value */
+ unsigned efuse_max_value;
+ /* current temperature sensing slope */
+ unsigned slope;
+};
+
+/* TMU device specific details and status */
+struct tmu_info {
+ /* base Address for the TMU */
+ struct exynos5_tmu_reg *tmu_base;
+ /* mux Address for the TMU */
+ int tmu_mux;
+ /* pre-defined values for calibration and thresholds */
+ struct tmu_data data;
+ /* value required for triminfo_25 calibration */
+ unsigned te1;
+ /* value required for triminfo_85 calibration */
+ unsigned te2;
+ /* Value for measured data calibration */
+ int dc_value;
+ /* enum value indicating status of the TMU */
+ int tmu_state;
+};
+
+/* Global struct tmu_info variable to store init values */
+static struct tmu_info gbl_info;
+
+/*
+ * Get current temperature code from register,
+ * then calculate and calibrate it's value
+ * in degree celsius.
+ *
+ * @return current temperature of the chip as sensed by TMU
+ */
+static int get_cur_temp(struct tmu_info *info)
+{
+ struct exynos5_tmu_reg *reg = info->tmu_base;
+ ulong start;
+ int cur_temp = 0;
+
+ /*
+ * Temperature code range between min 25 and max 125.
+ * May run more than once for first call as initial sensing
+ * has not yet happened.
+ */
+ if (info->tmu_state == TMU_STATUS_NORMAL) {
+ start = get_timer(0);
+ do {
+ cur_temp = readl(&reg->current_temp) & 0xff;
+ } while ((cur_temp == 0) || (get_timer(start) > 100));
+ }
+
+ if (cur_temp == 0)
+ return cur_temp;
+
+ /* Calibrate current temperature */
+ cur_temp = cur_temp - info->te1 + info->dc_value;
+
+ return cur_temp;
+}
+
+/*
+ * Monitors status of the TMU device and exynos temperature
+ *
+ * @param temp pointer to the current temperature value
+ * @return enum tmu_status_t value, code indicating event to execute
+ */
+enum tmu_status_t tmu_monitor(int *temp)
+{
+ int cur_temp;
+ struct tmu_data *data = &gbl_info.data;
+
+ if (gbl_info.tmu_state == TMU_STATUS_INIT)
+ return TMU_STATUS_INIT;
+
+ /* Read current temperature of the SOC */
+ cur_temp = get_cur_temp(&gbl_info);
+
+ if (!cur_temp)
+ goto out;
+
+ *temp = cur_temp;
+
+ /* Temperature code lies between min 25 and max 125 */
+ if ((cur_temp >= data->ts.start_tripping) &&
+ (cur_temp <= data->ts.max_val))
+ return TMU_STATUS_TRIPPED;
+
+ if (cur_temp >= data->ts.start_warning)
+ return TMU_STATUS_WARNING;
+
+ if ((cur_temp < data->ts.start_warning) &&
+ (cur_temp >= data->ts.min_val))
+ return TMU_STATUS_NORMAL;
+
+ out:
+ /* Temperature code does not lie between min 25 and max 125 */
+ gbl_info.tmu_state = TMU_STATUS_INIT;
+ debug("EXYNOS_TMU: Thermal reading failed\n");
+ return TMU_STATUS_INIT;
+}
+
+/*
+ * Get TMU specific pre-defined values from FDT
+ *
+ * @param info pointer to the tmu_info struct
+ * @param blob FDT blob
+ * @return int value, 0 for success
+ */
+static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
+{
+#ifdef CONFIG_OF_CONTROL
+ fdt_addr_t addr;
+ int node;
+ int error = 0;
+
+ /* Get the node from FDT for TMU */
+ node = fdtdec_next_compatible(blob, 0,
+ COMPAT_SAMSUNG_EXYNOS_TMU);
+ if (node < 0) {
+ debug("EXYNOS_TMU: No node for tmu in device tree\n");
+ return -1;
+ }
+
+ /*
+ * Get the pre-defined TMU specific values from FDT.
+ * All of these are expected to be correct otherwise
+ * miscalculation of register values in tmu_setup_parameters
+ * may result in misleading current temperature.
+ */
+ addr = fdtdec_get_addr(blob, node, "reg");
+ if (addr == FDT_ADDR_T_NONE) {
+ debug("%s: Missing tmu-base\n", __func__);
+ return -1;
+ }
+ info->tmu_base = (struct exynos5_tmu_reg *)addr;
+
+ /* Optional field. */
+ info->tmu_mux = fdtdec_get_int(blob,
+ node, "samsung,mux", -1);
+ /* Take default value as per the user manual b(110) */
+ if (info->tmu_mux == -1)
+ info->tmu_mux = 0x6;
+
+ info->data.ts.min_val = fdtdec_get_int(blob,
+ node, "samsung,min-temp", -1);
+ error |= (info->data.ts.min_val == -1);
+ info->data.ts.max_val = fdtdec_get_int(blob,
+ node, "samsung,max-temp", -1);
+ error |= (info->data.ts.max_val == -1);
+ info->data.ts.start_warning = fdtdec_get_int(blob,
+ node, "samsung,start-warning", -1);
+ error |= (info->data.ts.start_warning == -1);
+ info->data.ts.start_tripping = fdtdec_get_int(blob,
+ node, "samsung,start-tripping", -1);
+ error |= (info->data.ts.start_tripping == -1);
+ info->data.ts.hardware_tripping = fdtdec_get_int(blob,
+ node, "samsung,hw-tripping", -1);
+ error |= (info->data.ts.hardware_tripping == -1);
+ info->data.efuse_min_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-min-value", -1);
+ error |= (info->data.efuse_min_value == -1);
+ info->data.efuse_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-value", -1);
+ error |= (info->data.efuse_value == -1);
+ info->data.efuse_max_value = fdtdec_get_int(blob,
+ node, "samsung,efuse-max-value", -1);
+ error |= (info->data.efuse_max_value == -1);
+ info->data.slope = fdtdec_get_int(blob,
+ node, "samsung,slope", -1);
+ error |= (info->data.slope == -1);
+ info->dc_value = fdtdec_get_int(blob,
+ node, "samsung,dc-value", -1);
+ error |= (info->dc_value == -1);
+
+ if (error) {
+ debug("fail to get tmu node properties\n");
+ return -1;
+ }
+#else
+ /* Non DT support may never be added. Just in case */
+ return -1;
+#endif
+
+ return 0;
+}
+
+/*
+ * Calibrate and calculate threshold values and
+ * enable interrupt levels
+ *
+ * @param info pointer to the tmu_info struct
+ */
+static void tmu_setup_parameters(struct tmu_info *info)
+{
+ unsigned te_code, con;
+ unsigned warning_code, trip_code, hwtrip_code;
+ unsigned cooling_temp;
+ unsigned rising_value;
+ struct tmu_data *data = &info->data;
+ struct exynos5_tmu_reg *reg = info->tmu_base;
+
+ /* Must reload for reading efuse value from triminfo register */
+ writel(TRIMINFO_RELOAD, &reg->triminfo_control);
+
+ /* Get the compensation parameter */
+ te_code = readl(&reg->triminfo);
+ info->te1 = te_code & TRIM_INFO_MASK;
+ info->te2 = ((te_code >> 8) & TRIM_INFO_MASK);
+
+ if ((data->efuse_min_value > info->te1) ||
+ (info->te1 > data->efuse_max_value)
+ || (info->te2 != 0))
+ info->te1 = data->efuse_value;
+
+ /* Get RISING & FALLING Threshold value */
+ warning_code = data->ts.start_warning
+ + info->te1 - info->dc_value;
+ trip_code = data->ts.start_tripping
+ + info->te1 - info->dc_value;
+ hwtrip_code = data->ts.hardware_tripping
+ + info->te1 - info->dc_value;
+
+ cooling_temp = 0;
+
+ rising_value = ((warning_code << 8) |
+ (trip_code << 16) |
+ (hwtrip_code << 24));
+
+ /* Set interrupt level */
+ writel(rising_value, &reg->threshold_temp_rise);
+ writel(cooling_temp, &reg->threshold_temp_fall);
+
+ /*
+ * Init TMU control tuning parameters
+ * [28:24] VREF - Voltage reference
+ * [15:13] THERM_TRIP_MODE - Tripping mode
+ * [12] THERM_TRIP_EN - Thermal tripping enable
+ * [11:8] BUF_SLOPE_SEL - Gain of amplifier
+ * [6] THERM_TRIP_BY_TQ_EN - Tripping by TQ pin
+ */
+ writel(data->slope, &reg->tmu_control);
+
+ writel(INTCLEARALL, &reg->intclear);
+
+ /* TMU core enable */
+ con = readl(&reg->tmu_control);
+ con |= THERM_TRIP_EN | CORE_EN | (info->tmu_mux << 20);
+
+ writel(con, &reg->tmu_control);
+
+ /* Enable HW thermal trip */
+ set_hw_thermal_trip();
+
+ /* LEV1 LEV2 interrupt enable */
+ writel(INTEN_RISE1 | INTEN_RISE2, &reg->inten);
+}
+
+/*
+ * Initialize TMU device
+ *
+ * @param blob FDT blob
+ * @return int value, 0 for success
+ */
+int tmu_init(const void *blob)
+{
+ gbl_info.tmu_state = TMU_STATUS_INIT;
+ if (get_tmu_fdt_values(&gbl_info, blob) < 0)
+ goto ret;
+
+ tmu_setup_parameters(&gbl_info);
+ gbl_info.tmu_state = TMU_STATUS_NORMAL;
+ret:
+ return gbl_info.tmu_state;
+}
diff --git a/qemu/roms/u-boot/drivers/power/ftpmu010.c b/qemu/roms/u-boot/drivers/power/ftpmu010.c
new file mode 100644
index 000000000..78128c641
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/ftpmu010.c
@@ -0,0 +1,88 @@
+/*
+ * (C) Copyright 2009 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * Copyright (C) 2010 Andes Technology Corporation
+ * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
+ * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/ftpmu010.h>
+
+/* OSCC: OSC Control Register */
+void ftpmu010_32768osc_enable(void)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int oscc;
+
+ /* enable the 32768Hz oscillator */
+ oscc = readl(&pmu->OSCC);
+ oscc &= ~(FTPMU010_OSCC_OSCL_OFF | FTPMU010_OSCC_OSCL_TRI);
+ writel(oscc, &pmu->OSCC);
+
+ /* wait until ready */
+ while (!(readl(&pmu->OSCC) & FTPMU010_OSCC_OSCL_STABLE))
+ ;
+
+ /* select 32768Hz oscillator */
+ oscc = readl(&pmu->OSCC);
+ oscc |= FTPMU010_OSCC_OSCL_RTCLSEL;
+ writel(oscc, &pmu->OSCC);
+}
+
+/* MFPSR: Multi-Function Port Setting Register */
+void ftpmu010_mfpsr_select_dev(unsigned int dev)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int mfpsr;
+
+ mfpsr = readl(&pmu->MFPSR);
+ mfpsr |= dev;
+ writel(mfpsr, &pmu->MFPSR);
+}
+
+void ftpmu010_mfpsr_diselect_dev(unsigned int dev)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int mfpsr;
+
+ mfpsr = readl(&pmu->MFPSR);
+ mfpsr &= ~dev;
+ writel(mfpsr, &pmu->MFPSR);
+}
+
+/* PDLLCR0: PLL/DLL Control Register 0 */
+void ftpmu010_dlldis_disable(void)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int pdllcr0;
+
+ pdllcr0 = readl(&pmu->PDLLCR0);
+ pdllcr0 |= FTPMU010_PDLLCR0_DLLDIS;
+ writel(pdllcr0, &pmu->PDLLCR0);
+}
+
+void ftpmu010_sdram_clk_disable(unsigned int cr0)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int pdllcr0;
+
+ pdllcr0 = readl(&pmu->PDLLCR0);
+ pdllcr0 |= FTPMU010_PDLLCR0_HCLKOUTDIS(cr0);
+ writel(pdllcr0, &pmu->PDLLCR0);
+}
+
+/* SDRAMHTC: SDRAM Signal Hold Time Control */
+void ftpmu010_sdramhtc_set(unsigned int val)
+{
+ static struct ftpmu010 *pmu = (struct ftpmu010 *)CONFIG_FTPMU010_BASE;
+ unsigned int sdramhtc;
+
+ sdramhtc = readl(&pmu->SDRAMHTC);
+ sdramhtc |= val;
+ writel(sdramhtc, &pmu->SDRAMHTC);
+}
diff --git a/qemu/roms/u-boot/drivers/power/fuel_gauge/Makefile b/qemu/roms/u-boot/drivers/power/fuel_gauge/Makefile
new file mode 100644
index 000000000..3b349f939
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/fuel_gauge/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_POWER_FG_MAX17042) += fg_max17042.o
diff --git a/qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c b/qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c
new file mode 100644
index 000000000..154ca6a69
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/fuel_gauge/fg_max17042.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max17042_fg.h>
+#include <i2c.h>
+#include <power/max8997_pmic.h>
+#include <power/power_chrg.h>
+#include <power/battery.h>
+#include <power/fg_battery_cell_params.h>
+#include <errno.h>
+
+static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++, addr++) {
+ ret = pmic_reg_write(p, addr, *(data + i));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+ unsigned int dat;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++, addr++) {
+ ret = pmic_reg_read(p, addr, &dat);
+ if (ret)
+ return ret;
+
+ *(data + i) = (u16)dat;
+ }
+
+ return 0;
+}
+
+static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
+{
+ unsigned int val = data;
+ int ret = 0;
+
+ ret |= pmic_reg_write(p, addr, val);
+ ret |= pmic_reg_read(p, addr, &val);
+
+ if (ret)
+ return ret;
+
+ if (((u16) val) == data)
+ return 0;
+
+ return -1;
+}
+
+static void por_fuelgauge_init(struct pmic *p)
+{
+ u16 r_data0[16], r_data1[16], r_data2[16];
+ u32 rewrite_count = 5;
+ u32 check_count;
+ u32 lock_count;
+ u32 i = 0;
+ u32 val;
+ s32 ret = 0;
+ char *status_msg;
+
+ /* Delay 500 ms */
+ mdelay(500);
+ /* Initilize Configuration */
+ pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
+
+rewrite_model:
+ check_count = 5;
+ lock_count = 5;
+
+ if (!rewrite_count--) {
+ status_msg = "init failed!";
+ goto error;
+ }
+
+ /* Unlock Model Access */
+ pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
+ pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
+
+ /* Write/Read/Verify the Custom Model */
+ ret = fg_write_regs(p, MAX17042_MODEL1, cell_character0,
+ ARRAY_SIZE(cell_character0));
+ if (ret)
+ goto rewrite_model;
+
+ ret = fg_write_regs(p, MAX17042_MODEL2, cell_character1,
+ ARRAY_SIZE(cell_character1));
+ if (ret)
+ goto rewrite_model;
+
+ ret = fg_write_regs(p, MAX17042_MODEL3, cell_character2,
+ ARRAY_SIZE(cell_character2));
+ if (ret)
+ goto rewrite_model;
+
+check_model:
+ if (!check_count--) {
+ if (rewrite_count)
+ goto rewrite_model;
+ else
+ status_msg = "check failed!";
+
+ goto error;
+ }
+
+ ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+ if (ret)
+ goto check_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+ if (ret)
+ goto check_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+ if (ret)
+ goto check_model;
+
+ for (i = 0; i < 16; i++) {
+ if ((cell_character0[i] != r_data0[i])
+ || (cell_character1[i] != r_data1[i])
+ || (cell_character2[i] != r_data2[i]))
+ goto rewrite_model;
+ }
+
+lock_model:
+ if (!lock_count--) {
+ if (rewrite_count)
+ goto rewrite_model;
+ else
+ status_msg = "lock failed!";
+
+ goto error;
+ }
+
+ /* Lock model access */
+ pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
+ pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
+
+ /* Verify the model access is locked */
+ ret = fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+ if (ret)
+ goto lock_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+ if (ret)
+ goto lock_model;
+
+ ret = fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+ if (ret)
+ goto lock_model;
+
+ for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
+ /* Check if model locked */
+ if (r_data0[i] || r_data1[i] || r_data2[i])
+ goto lock_model;
+ }
+
+ /* Write Custom Parameters */
+ fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
+ fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
+
+ /* Delay at least 350mS */
+ mdelay(350);
+
+ /* Initialization Complete */
+ pmic_reg_read(p, MAX17042_STATUS, &val);
+ /* Write and Verify Status with POR bit Cleared */
+ fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
+
+ /* Delay at least 350 ms */
+ mdelay(350);
+
+ status_msg = "OK!";
+error:
+ debug("%s: model init status: %s\n", p->name, status_msg);
+ return;
+}
+
+static int power_update_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max17042 fuel gauge\n");
+ return -1;
+ }
+
+ ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
+ pb->bat->state_of_chrg = (val >> 8);
+
+ pmic_reg_read(p, MAX17042_VCELL, &val);
+ debug("vfsoc: 0x%x\n", val);
+ pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
+ pb->bat->voltage_uV = (pb->bat->voltage_uV * 625);
+
+ pmic_reg_read(p, 0x05, &val);
+ pb->bat->capacity = val >> 2;
+
+ return ret;
+}
+
+static int power_check_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max17042 fuel gauge\n");
+ return -1;
+ }
+
+ ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
+ debug("fg status: 0x%x\n", val);
+
+ if (val & MAX17042_POR)
+ por_fuelgauge_init(p);
+
+ ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
+ pb->bat->version = val;
+
+ power_update_battery(p, bat);
+ debug("fg ver: 0x%x\n", pb->bat->version);
+ printf("BAT: state_of_charge(SOC):%d%%\n",
+ pb->bat->state_of_chrg);
+
+ printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
+ pb->bat->voltage_uV / 1000000,
+ pb->bat->voltage_uV % 1000000,
+ pb->bat->capacity);
+
+ if (pb->bat->voltage_uV > 3850000)
+ pb->bat->state = EXT_SOURCE;
+ else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
+ pb->bat->state = CHARGE;
+ else
+ pb->bat->state = NORMAL;
+
+ return ret;
+}
+
+static struct power_fg power_fg_ops = {
+ .fg_battery_check = power_check_battery,
+ .fg_battery_update = power_update_battery,
+};
+
+int power_fg_init(unsigned char bus)
+{
+ static const char name[] = "MAX17042_FG";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Fuel Gauge init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = FG_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX17042_I2C_ADDR;
+ p->hw.i2c.tx_num = 2;
+ p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
+ p->bus = bus;
+
+ p->fg = &power_fg_ops;
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/mfd/Makefile b/qemu/roms/u-boot/drivers/power/mfd/Makefile
new file mode 100644
index 000000000..43afe842a
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/mfd/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2013 Samsung Electronics
+# Piotr Wilczek <p.wilczek@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_POWER_PMIC_MAX77693) += pmic_max77693.o
+obj-$(CONFIG_POWER_MUIC_MAX77693) += muic_max77693.o
+obj-$(CONFIG_POWER_FG_MAX77693) += fg_max77693.o
diff --git a/qemu/roms/u-boot/drivers/power/mfd/fg_max77693.c b/qemu/roms/u-boot/drivers/power/mfd/fg_max77693.c
new file mode 100644
index 000000000..4519fed49
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/mfd/fg_max77693.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max77693_fg.h>
+#include <i2c.h>
+#include <power/power_chrg.h>
+#include <power/battery.h>
+#include <power/fg_battery_cell_params.h>
+#include <errno.h>
+
+static int max77693_get_vcell(u32 *vcell)
+{
+ u16 value;
+ u8 ret;
+
+ ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VCELL, 1,
+ (u8 *)&value, 2);
+ if (ret)
+ return ret;
+
+ *vcell = (u32)(value >> 3);
+ *vcell = *vcell * 625;
+
+ return 0;
+}
+
+static int max77693_get_soc(u32 *soc)
+{
+ u16 value;
+ u8 ret;
+
+ ret = i2c_read(MAX77693_FUEL_I2C_ADDR, MAX77693_VFSOC, 1,
+ (u8 *)&value, 2);
+ if (ret)
+ return ret;
+
+ *soc = (u32)(value >> 8);
+
+ return 0;
+}
+
+static int power_update_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ int ret;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max77693 fuel gauge\n");
+ return -1;
+ }
+
+ ret = max77693_get_soc(&pb->bat->state_of_chrg);
+ if (ret)
+ return ret;
+
+ max77693_get_vcell(&pb->bat->voltage_uV);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int power_check_battery(struct pmic *p, struct pmic *bat)
+{
+ struct power_battery *pb = bat->pbat;
+ unsigned int val;
+ int ret = 0;
+
+ if (pmic_probe(p)) {
+ puts("Can't find max77693 fuel gauge\n");
+ return -1;
+ }
+
+ ret = pmic_reg_read(p, MAX77693_STATUS, &val);
+ if (ret)
+ return ret;
+ debug("fg status: 0x%x\n", val);
+
+ ret = pmic_reg_read(p, MAX77693_VERSION, &pb->bat->version);
+ if (ret)
+ return ret;
+
+ ret = power_update_battery(p, bat);
+ if (ret)
+ return ret;
+ debug("fg ver: 0x%x\n", pb->bat->version);
+ printf("BAT: state_of_charge(SOC):%d%%\n",
+ pb->bat->state_of_chrg);
+
+ printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n",
+ pb->bat->voltage_uV / 1000000,
+ pb->bat->voltage_uV % 1000000,
+ pb->bat->capacity);
+
+ if (pb->bat->voltage_uV > 3850000)
+ pb->bat->state = EXT_SOURCE;
+ else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5)
+ pb->bat->state = CHARGE;
+ else
+ pb->bat->state = NORMAL;
+
+ return 0;
+}
+
+static struct power_fg power_fg_ops = {
+ .fg_battery_check = power_check_battery,
+ .fg_battery_update = power_update_battery,
+};
+
+int power_fg_init(unsigned char bus)
+{
+ static const char name[] = "MAX77693_FG";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Fuel Gauge init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = FG_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_FUEL_I2C_ADDR;
+ p->hw.i2c.tx_num = 2;
+ p->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG;
+ p->bus = bus;
+
+ p->fg = &power_fg_ops;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/mfd/muic_max77693.c b/qemu/roms/u-boot/drivers/power/mfd/muic_max77693.c
new file mode 100644
index 000000000..e71012de1
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/mfd/muic_max77693.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/power_chrg.h>
+#include <power/max77693_muic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int power_chrg_get_type(struct pmic *p)
+{
+ unsigned int val;
+ unsigned int charge_type, charger;
+
+ /* if probe failed, return cable none */
+ if (pmic_probe(p))
+ return CHARGER_NO;
+
+ pmic_reg_read(p, MAX77693_MUIC_STATUS2, &val);
+
+ charge_type = val & MAX77693_MUIC_CHG_MASK;
+
+ switch (charge_type) {
+ case MAX77693_MUIC_CHG_NO:
+ charger = CHARGER_NO;
+ break;
+ case MAX77693_MUIC_CHG_USB:
+ case MAX77693_MUIC_CHG_USB_D:
+ charger = CHARGER_USB;
+ break;
+ case MAX77693_MUIC_CHG_TA:
+ case MAX77693_MUIC_CHG_TA_1A:
+ charger = CHARGER_TA;
+ break;
+ case MAX77693_MUIC_CHG_TA_500:
+ charger = CHARGER_TA_500;
+ break;
+ default:
+ charger = CHARGER_UNKNOWN;
+ break;
+ }
+
+ return charger;
+}
+
+static struct power_chrg power_chrg_muic_ops = {
+ .chrg_type = power_chrg_get_type,
+};
+
+int power_muic_init(unsigned int bus)
+{
+ static const char name[] = "MAX77693_MUIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Micro USB Interface Controller init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = MUIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_MUIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_muic_ops;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/mfd/pmic_max77693.c b/qemu/roms/u-boot/drivers/power/mfd/pmic_max77693.c
new file mode 100644
index 000000000..1a4416b54
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/mfd/pmic_max77693.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics
+ * Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max77693_pmic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int max77693_charger_state(struct pmic *p, int state, int current)
+{
+ unsigned int val;
+
+ if (pmic_probe(p))
+ return -1;
+
+ /* unlock write capability */
+ val = MAX77693_CHG_UNLOCK;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_06, val);
+
+ if (state == CHARGER_DISABLE) {
+ puts("Disable the charger.\n");
+ pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val);
+ val &= ~0x01;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_00, val);
+ return -1;
+ }
+
+ if (current < CHARGER_MIN_CURRENT || current > CHARGER_MAX_CURRENT) {
+ printf("%s: Wrong charge current: %d [mA]\n",
+ __func__, current);
+ return -1;
+ }
+
+ /* set charging current */
+ pmic_reg_read(p, MAX77693_CHG_CNFG_02, &val);
+ val &= ~MAX77693_CHG_CC;
+ val |= current * 10 / 333; /* 0.1A/3 steps */
+ pmic_reg_write(p, MAX77693_CHG_CNFG_02, val);
+
+ /* enable charging */
+ val = MAX77693_CHG_MODE_ON;
+ pmic_reg_write(p, MAX77693_CHG_CNFG_00, val);
+
+ /* check charging current */
+ pmic_reg_read(p, MAX77693_CHG_CNFG_02, &val);
+ val &= 0x3f;
+ printf("Enable the charger @ %d [mA]\n", val * 333 / 10);
+
+ return 0;
+}
+
+static int max77693_charger_bat_present(struct pmic *p)
+{
+ unsigned int val;
+
+ if (pmic_probe(p))
+ return -1;
+
+ pmic_reg_read(p, MAX77693_CHG_INT_OK, &val);
+
+ return !(val & MAX77693_CHG_DETBAT);
+}
+
+static struct power_chrg power_chrg_pmic_ops = {
+ .chrg_bat_present = max77693_charger_bat_present,
+ .chrg_state = max77693_charger_state,
+};
+
+int pmic_init_max77693(unsigned char bus)
+{
+ static const char name[] = "MAX77693_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board PMIC init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX77693_PMIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_pmic_ops;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/palmas.c b/qemu/roms/u-boot/drivers/power/palmas.c
new file mode 100644
index 000000000..cfbc9dc52
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/palmas.c
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2012-2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <config.h>
+#include <palmas.h>
+
+void palmas_init_settings(void)
+{
+#ifdef CONFIG_PALMAS_SMPS7_FPWM
+ int err;
+ /*
+ * Set SMPS7 (1.8 V I/O supply on platforms with TWL6035/37) to
+ * forced PWM mode. This reduces noise (but affects efficiency).
+ */
+ u8 val = SMPS_MODE_SLP_FPWM | SMPS_MODE_ACT_FPWM;
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS7_CTRL, val);
+ if (err)
+ printf("palmas: could not force PWM for SMPS7: err = %d\n",
+ err);
+#endif
+}
+
+int palmas_mmc1_poweron_ldo(void)
+{
+ u8 val = 0;
+
+#if defined(CONFIG_DRA7XX)
+ /*
+ * Currently valid for the dra7xx_evm board:
+ * Set TPS659038 LDO1 to 3.0 V
+ */
+ val = LDO_VOLT_3V0;
+ if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_VOLTAGE, val)) {
+ printf("tps65903x: could not set LDO1 voltage.\n");
+ return 1;
+ }
+ /* TURN ON LDO1 */
+ val = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_CTRL, val)) {
+ printf("tps65903x: could not turn on LDO1.\n");
+ return 1;
+ }
+ return 0;
+#else
+ /*
+ * We assume that this is a OMAP543X + TWL603X board:
+ * Set TWL6035/37 LDO9 to 3.0 V
+ */
+ val = LDO_VOLT_3V0;
+ return twl603x_mmc1_set_ldo9(val);
+#endif
+}
+
+/*
+ * On some OMAP5 + TWL603X hardware the SD card socket and LDO9_IN are
+ * powered by an external 3.3 V regulator, while the output of LDO9
+ * supplies VDDS_SDCARD for the OMAP5 interface only. This implies that
+ * LDO9 could be set to 'bypass' mode when required (e.g. for 3.3 V cards).
+ */
+int twl603x_mmc1_set_ldo9(u8 vsel)
+{
+ u8 cval = 0, vval = 0; /* Off by default */
+ int err;
+
+ if (vsel) {
+ /* Turn on */
+ if (vsel > LDO_VOLT_3V3) {
+ /* Put LDO9 in bypass */
+ cval = LDO9_BYP_EN | RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = LDO_VOLT_3V3;
+ } else {
+ cval = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = vsel & 0x3f;
+ }
+ }
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set LDO9 %s: err = %d\n",
+ vsel > LDO_VOLT_3V3 ? "bypass" : "voltage", err);
+ return err;
+ }
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_CTRL, cval);
+ if (err)
+ printf("twl603x: could not turn %s LDO9: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+}
+
+#ifdef CONFIG_PALMAS_AUDPWR
+/*
+ * Turn audio codec power and 32 kHz clock on/off. Use for
+ * testing OMAP543X + TWL603X + TWL604X boards only.
+ */
+int twl603x_audio_power(u8 on)
+{
+ u8 cval = 0, vval = 0, c32k = 0;
+ int err;
+
+ if (on) {
+ vval = SMPS_VOLT_2V1;
+ cval = SMPS_MODE_SLP_AUTO | SMPS_MODE_ACT_AUTO;
+ c32k = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ }
+ /* Set SMPS9 to 2.1 V (for TWL604x), or to 0 (off) */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set SMPS9 voltage: err = %d\n",
+ err);
+ return err;
+ }
+ /* Turn on or off SMPS9 */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_CTRL, cval);
+ if (err) {
+ printf("twl603x: could not turn SMPS9 %s: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+ }
+ /* Output 32 kHz clock on or off */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, CLK32KGAUDIO_CTRL, c32k);
+ if (err)
+ printf("twl603x: could not turn CLK32KGAUDIO %s: err = %d\n",
+ c32k ? "on" : "off", err);
+ return err;
+}
+#endif
+
+#ifdef CONFIG_PALMAS_USB_SS_PWR
+/**
+ * @brief palmas_enable_ss_ldo - Configure EVM board specific configurations
+ * for the USB Super speed SMPS10 regulator.
+ *
+ * @return 0
+ */
+int palmas_enable_ss_ldo(void)
+{
+ /* Enable smps10 regulator */
+ return palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS10_CTRL,
+ SMPS10_MODE_ACTIVE_D);
+}
+#endif
+
+/*
+ * Enable/disable back-up battery (or super cap) charging on TWL6035/37.
+ * Please use defined BB_xxx values.
+ */
+int twl603x_enable_bb_charge(u8 bb_fields)
+{
+ u8 val = bb_fields & 0x0f;
+ int err;
+
+ val |= (VRTC_EN_SLP | VRTC_EN_OFF | VRTC_PWEN);
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, BB_VRTC_CTRL, val);
+ if (err)
+ printf("twl603x: could not set BB_VRTC_CTRL to 0x%02x: err = %d\n",
+ val, err);
+ return err;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/Makefile b/qemu/roms/u-boot/drivers/power/pmic/Makefile
new file mode 100644
index 000000000..4129bdabf
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2012 Samsung Electronics
+# Lukasz Majewski <l.majewski@samsung.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
+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_TPS65217) += pmic_tps65217.o
+obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o
diff --git a/qemu/roms/u-boot/drivers/power/pmic/muic_max8997.c b/qemu/roms/u-boot/drivers/power/pmic/muic_max8997.c
new file mode 100644
index 000000000..720342e5e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/muic_max8997.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/power_chrg.h>
+#include <power/max8997_muic.h>
+#include <i2c.h>
+#include <errno.h>
+
+static int power_chrg_get_type(struct pmic *p)
+{
+ unsigned int val;
+ unsigned char charge_type, charger;
+
+ if (pmic_probe(p))
+ return CHARGER_NO;
+
+ pmic_reg_read(p, MAX8997_MUIC_STATUS2, &val);
+ charge_type = val & MAX8997_MUIC_CHG_MASK;
+
+ switch (charge_type) {
+ case MAX8997_MUIC_CHG_NO:
+ charger = CHARGER_NO;
+ break;
+ case MAX8997_MUIC_CHG_USB:
+ case MAX8997_MUIC_CHG_USB_D:
+ charger = CHARGER_USB;
+ break;
+ case MAX8997_MUIC_CHG_TA:
+ case MAX8997_MUIC_CHG_TA_1A:
+ charger = CHARGER_TA;
+ break;
+ case MAX8997_MUIC_CHG_TA_500:
+ charger = CHARGER_TA_500;
+ break;
+ default:
+ charger = CHARGER_UNKNOWN;
+ break;
+ }
+
+ return charger;
+}
+
+static struct power_chrg power_chrg_muic_ops = {
+ .chrg_type = power_chrg_get_type,
+};
+
+int power_muic_init(unsigned int bus)
+{
+ static const char name[] = "MAX8997_MUIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board Micro USB Interface Controller init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = MUIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX8997_MUIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_muic_ops;
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_max77686.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_max77686.c
new file mode 100644
index 000000000..d4c430e22
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_max77686.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Rajeshwari Shinde <rajeshwari.s@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/max77686_pmic.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char max77686_buck_addr[] = {
+ 0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
+};
+
+static unsigned int max77686_ldo_volt2hex(int ldo, ulong uV)
+{
+ unsigned int hex = 0;
+
+ switch (ldo) {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 15:
+ hex = (uV - 800000) / 25000;
+ break;
+ default:
+ hex = (uV - 800000) / 50000;
+ }
+
+ if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX)
+ return hex;
+
+ debug("%s: %ld is wrong voltage value for LDO%d\n", __func__, uV, ldo);
+ return 0;
+}
+
+int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV)
+{
+ unsigned int val, ret, hex, adr;
+
+ if (ldo < 1 && ldo > 26) {
+ printf("%s: %d is wrong ldo number\n", __func__, ldo);
+ return -1;
+ }
+
+ adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+ hex = max77686_ldo_volt2hex(ldo, uV);
+
+ if (!hex)
+ return -1;
+
+ ret = pmic_reg_read(p, adr, &val);
+ if (ret)
+ return ret;
+
+ val &= ~MAX77686_LDO_VOLT_MASK;
+ val |= hex;
+ ret |= pmic_reg_write(p, adr, val);
+
+ return ret;
+}
+
+int max77686_set_ldo_mode(struct pmic *p, int ldo, char opmode)
+{
+ unsigned int val, ret, adr, mode;
+
+ if (ldo < 1 && 26 < ldo) {
+ printf("%s: %d is wrong ldo number\n", __func__, ldo);
+ return -1;
+ }
+
+ adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+
+ /* mode */
+ switch (opmode) {
+ case OPMODE_OFF:
+ mode = MAX77686_LDO_MODE_OFF;
+ break;
+ case OPMODE_STANDBY:
+ switch (ldo) {
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ case 16:
+ mode = MAX77686_LDO_MODE_STANDBY;
+ break;
+ default:
+ mode = 0xff;
+ }
+ break;
+ case OPMODE_LPM:
+ mode = MAX77686_LDO_MODE_LPM;
+ break;
+ case OPMODE_ON:
+ mode = MAX77686_LDO_MODE_ON;
+ break;
+ default:
+ mode = 0xff;
+ }
+
+ if (mode == 0xff) {
+ printf("%s: %d is not supported on LDO%d\n",
+ __func__, opmode, ldo);
+ return -1;
+ }
+
+ ret = pmic_reg_read(p, adr, &val);
+ if (ret)
+ return ret;
+
+ val &= ~MAX77686_LDO_MODE_MASK;
+ val |= mode;
+ ret |= pmic_reg_write(p, adr, val);
+
+ return ret;
+}
+
+int max77686_set_buck_mode(struct pmic *p, int buck, char opmode)
+{
+ unsigned int val, ret, mask, adr, size, mode, mode_shift;
+
+ size = ARRAY_SIZE(max77686_buck_addr);
+ if (buck >= size) {
+ printf("%s: %d is wrong buck number\n", __func__, buck);
+ return -1;
+ }
+
+ adr = max77686_buck_addr[buck];
+
+ /* mask */
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ mode_shift = MAX77686_BUCK_MODE_SHIFT_2;
+ break;
+ default:
+ mode_shift = MAX77686_BUCK_MODE_SHIFT_1;
+ }
+
+ mask = MAX77686_BUCK_MODE_MASK << mode_shift;
+
+ /* mode */
+ switch (opmode) {
+ case OPMODE_OFF:
+ mode = MAX77686_BUCK_MODE_OFF;
+ break;
+ case OPMODE_STANDBY:
+ switch (buck) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ mode = MAX77686_BUCK_MODE_STANDBY << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+ break;
+ case OPMODE_LPM:
+ switch (buck) {
+ case 2:
+ case 3:
+ case 4:
+ mode = MAX77686_BUCK_MODE_LPM << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+ break;
+ case OPMODE_ON:
+ mode = MAX77686_BUCK_MODE_ON << mode_shift;
+ break;
+ default:
+ mode = 0xff;
+ }
+
+ if (mode == 0xff) {
+ printf("%s: %d is not supported on BUCK%d\n",
+ __func__, opmode, buck);
+ return -1;
+ }
+
+ ret = pmic_reg_read(p, adr, &val);
+ if (ret)
+ return ret;
+
+ val &= ~mask;
+ val |= mode;
+ ret |= pmic_reg_write(p, adr, val);
+
+ return ret;
+}
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "MAX77686_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_OF_CONTROL
+ const void *blob = gd->fdt_blob;
+ int node, parent;
+
+ node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC);
+ if (node < 0) {
+ debug("PMIC: No node for PMIC Chip in device tree\n");
+ debug("node = %d\n", node);
+ return -1;
+ }
+
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("%s: Cannot find node parent\n", __func__);
+ return -1;
+ }
+
+ p->bus = i2c_get_bus_num_fdt(parent);
+ if (p->bus < 0) {
+ debug("%s: Cannot find I2C bus\n", __func__);
+ return -1;
+ }
+ p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9);
+#else
+ p->bus = bus;
+ p->hw.i2c.addr = MAX77686_I2C_ADDR;
+#endif
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.tx_num = 1;
+
+ puts("Board PMIC init\n");
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_max8997.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_max8997.c
new file mode 100644
index 000000000..ba0169232
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_max8997.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max8997_pmic.h>
+#include <i2c.h>
+#include <errno.h>
+
+unsigned char max8997_reg_ldo(int uV)
+{
+ unsigned char ret;
+ if (uV <= 800000)
+ return 0;
+ if (uV >= 3950000)
+ return MAX8997_LDO_MAX_VAL;
+ ret = (uV - 800000) / 50000;
+ if (ret > MAX8997_LDO_MAX_VAL) {
+ printf("MAX8997 LDO SETTING ERROR (%duV) -> %u\n", uV, ret);
+ ret = MAX8997_LDO_MAX_VAL;
+ }
+
+ return ret;
+}
+
+static int pmic_charger_state(struct pmic *p, int state, int current)
+{
+ unsigned char fc;
+ u32 val = 0;
+
+ if (pmic_probe(p))
+ return -1;
+
+ if (state == CHARGER_DISABLE) {
+ puts("Disable the charger.\n");
+ pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val);
+ val &= ~(MBCHOSTEN | VCHGR_FC);
+ pmic_reg_write(p, MAX8997_REG_MBCCTRL2, val);
+
+ return -1;
+ }
+
+ if (current < CHARGER_MIN_CURRENT || current > CHARGER_MAX_CURRENT) {
+ printf("%s: Wrong charge current: %d [mA]\n",
+ __func__, current);
+ return -1;
+ }
+
+ fc = (current - CHARGER_MIN_CURRENT) / CHARGER_CURRENT_RESOLUTION;
+ fc = fc & 0xf; /* up to 950 mA */
+
+ printf("Enable the charger @ %d [mA]\n", fc * CHARGER_CURRENT_RESOLUTION
+ + CHARGER_MIN_CURRENT);
+
+ val = fc | MBCICHFCSET;
+ pmic_reg_write(p, MAX8997_REG_MBCCTRL4, val);
+
+ pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val);
+ val = MBCHOSTEN | VCHGR_FC; /* enable charger & fast charge */
+ pmic_reg_write(p, MAX8997_REG_MBCCTRL2, val);
+
+ return 0;
+}
+
+static int pmic_charger_bat_present(struct pmic *p)
+{
+ u32 val;
+
+ if (pmic_probe(p))
+ return -1;
+
+ pmic_reg_read(p, MAX8997_REG_STATUS4, &val);
+
+ return !(val & DETBAT);
+}
+
+static struct power_chrg power_chrg_pmic_ops = {
+ .chrg_bat_present = pmic_charger_bat_present,
+ .chrg_state = pmic_charger_state,
+};
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "MAX8997_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ debug("Board PMIC init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX8997_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ p->chrg = &power_chrg_pmic_ops;
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_max8998.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_max8998.c
new file mode 100644
index 000000000..ca2f504cc
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_max8998.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max8998_pmic.h>
+#include <errno.h>
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "MAX8998_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ puts("Board PMIC init\n");
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = MAX8998_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c
new file mode 100644
index 000000000..22c1f15ee
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Gateworks Corporation
+ * Tim Harvey <tharvey@gateworks.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/pfuze100_pmic.h>
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "PFUZE100_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_PFUZE100_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65217.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65217.c
new file mode 100644
index 000000000..36e9024bf
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65217.c
@@ -0,0 +1,109 @@
+/*
+ * (C) Copyright 2011-2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <power/tps65217.h>
+
+/**
+ * tps65217_reg_read() - Generic function that can read a TPS65217 register
+ * @src_reg: Source register address
+ * @src_val: Address of destination variable
+ * @return: 0 for success, not 0 on failure.
+ */
+int tps65217_reg_read(uchar src_reg, uchar *src_val)
+{
+ return i2c_read(TPS65217_CHIP_PM, src_reg, 1, src_val, 1);
+}
+
+/**
+ * tps65217_reg_write() - Generic function that can write a TPS65217 PMIC
+ * register or bit field regardless of protection
+ * level.
+ *
+ * @prot_level: Register password protection. Use
+ * TPS65217_PROT_LEVEL_NONE,
+ * TPS65217_PROT_LEVEL_1 or TPS65217_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 tps65217_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 != TPS65217_MASK_ALL_BITS) {
+ ret = i2c_read(TPS65217_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 ^ TPS65217_PASSWORD_UNLOCK;
+ ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1,
+ &xor_reg, 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1);
+ if (ret)
+ return ret;
+
+ if (prot_level == TPS65217_PROT_LEVEL_2) {
+ ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1,
+ &xor_reg, 1);
+ if (ret)
+ return ret;
+
+ ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * tps65217_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 tps65217_voltage_update(uchar dc_cntrl_reg, uchar volt_sel)
+{
+ if ((dc_cntrl_reg != TPS65217_DEFDCDC1) &&
+ (dc_cntrl_reg != TPS65217_DEFDCDC2) &&
+ (dc_cntrl_reg != TPS65217_DEFDCDC3))
+ return 1;
+
+ /* set voltage level */
+ if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, dc_cntrl_reg, volt_sel,
+ TPS65217_MASK_ALL_BITS))
+ return 1;
+
+ /* set GO bit to initiate voltage transition */
+ if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, TPS65217_DEFSLEW,
+ TPS65217_DCDC_GO, TPS65217_DCDC_GO))
+ return 1;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65910.c b/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65910.c
new file mode 100644
index 000000000..7ee1160e0
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/pmic/pmic_tps65910.c
@@ -0,0 +1,83 @@
+/*
+ * (C) Copyright 2011-2013
+ * Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <power/tps65910.h>
+
+/*
+ * tps65910_set_i2c_control() - Set the TPS65910 to be controlled via the I2C
+ * interface.
+ * @return: 0 on success, not 0 on failure
+ */
+int tps65910_set_i2c_control(void)
+{
+ int ret;
+ uchar buf;
+
+ /* VDD1/2 voltage selection register access by control i/f */
+ ret = i2c_read(TPS65910_CTRL_I2C_ADDR, TPS65910_DEVCTRL_REG, 1,
+ &buf, 1);
+
+ if (ret)
+ return ret;
+
+ buf |= TPS65910_DEVCTRL_REG_SR_CTL_I2C_SEL_CTL_I2C;
+
+ return i2c_write(TPS65910_CTRL_I2C_ADDR, TPS65910_DEVCTRL_REG, 1,
+ &buf, 1);
+}
+
+/*
+ * tps65910_voltage_update() - Voltage switching for MPU frequency switching.
+ * @module: mpu - 0, core - 1
+ * @vddx_op_vol_sel: vdd voltage to set
+ * @return: 0 on success, not 0 on failure
+ */
+int tps65910_voltage_update(unsigned int module, unsigned char vddx_op_vol_sel)
+{
+ uchar buf;
+ unsigned int reg_offset;
+ int ret;
+
+ if (module == MPU)
+ reg_offset = TPS65910_VDD1_OP_REG;
+ else
+ reg_offset = TPS65910_VDD2_OP_REG;
+
+ /* Select VDDx OP */
+ ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1);
+ if (ret)
+ return ret;
+
+ buf &= ~TPS65910_OP_REG_CMD_MASK;
+
+ ret = i2c_write(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1);
+ if (ret)
+ return ret;
+
+ /* Configure VDDx OP Voltage */
+ ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1);
+ if (ret)
+ return ret;
+
+ buf &= ~TPS65910_OP_REG_SEL_MASK;
+ buf |= vddx_op_vol_sel;
+
+ ret = i2c_write(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1);
+ if (ret)
+ return ret;
+
+ ret = i2c_read(TPS65910_CTRL_I2C_ADDR, reg_offset, 1, &buf, 1);
+ if (ret)
+ return ret;
+
+ if ((buf & TPS65910_OP_REG_SEL_MASK) != vddx_op_vol_sel)
+ return 1;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/power_core.c b/qemu/roms/u-boot/drivers/power/power_core.c
new file mode 100644
index 000000000..fe1f31602
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/power_core.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <power/pmic.h>
+
+static LIST_HEAD(pmic_list);
+
+int check_reg(struct pmic *p, u32 reg)
+{
+ if (reg >= p->number_of_regs) {
+ printf("<reg num> = %d is invalid. Should be less than %d\n",
+ reg, p->number_of_regs);
+ return -1;
+ }
+
+ return 0;
+}
+
+int pmic_set_output(struct pmic *p, u32 reg, int out, int on)
+{
+ u32 val;
+
+ if (pmic_reg_read(p, reg, &val))
+ return -1;
+
+ if (on)
+ val |= out;
+ else
+ val &= ~out;
+
+ if (pmic_reg_write(p, reg, val))
+ return -1;
+
+ return 0;
+}
+
+static void pmic_show_info(struct pmic *p)
+{
+ printf("PMIC: %s\n", p->name);
+}
+
+static int pmic_dump(struct pmic *p)
+{
+ int i, ret;
+ u32 val;
+
+ if (!p) {
+ puts("Wrong PMIC name!\n");
+ return -1;
+ }
+
+ pmic_show_info(p);
+ for (i = 0; i < p->number_of_regs; i++) {
+ ret = pmic_reg_read(p, i, &val);
+ if (ret)
+ puts("PMIC: Registers dump failed\n");
+
+ if (!(i % 8))
+ printf("\n0x%02x: ", i);
+
+ printf("%08x ", val);
+ }
+ puts("\n");
+ return 0;
+}
+
+struct pmic *pmic_alloc(void)
+{
+ struct pmic *p;
+
+ p = calloc(sizeof(*p), 1);
+ if (!p) {
+ printf("%s: No available memory for allocation!\n", __func__);
+ return NULL;
+ }
+
+ list_add_tail(&p->list, &pmic_list);
+
+ debug("%s: new pmic struct: 0x%p\n", __func__, p);
+
+ return p;
+}
+
+struct pmic *pmic_get(const char *s)
+{
+ struct pmic *p;
+
+ list_for_each_entry(p, &pmic_list, list) {
+ if (strcmp(p->name, s) == 0) {
+ debug("%s: pmic %s -> 0x%p\n", __func__, p->name, p);
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+const char *power_get_interface(int interface)
+{
+ const char *power_interface[] = {"I2C", "SPI", "|+|-|"};
+ return power_interface[interface];
+}
+
+static void pmic_list_names(void)
+{
+ struct pmic *p;
+
+ puts("PMIC devices:\n");
+ list_for_each_entry(p, &pmic_list, list) {
+ printf("name: %s bus: %s_%d\n", p->name,
+ power_get_interface(p->interface), p->bus);
+ }
+}
+
+int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u32 ret, reg, val;
+ char *cmd, *name;
+ struct pmic *p;
+
+ /* at least two arguments please */
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if (strcmp(argv[1], "list") == 0) {
+ pmic_list_names();
+ return CMD_RET_SUCCESS;
+ }
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ name = argv[1];
+ cmd = argv[2];
+
+ debug("%s: name: %s cmd: %s\n", __func__, name, cmd);
+ p = pmic_get(name);
+ if (!p)
+ return CMD_RET_FAILURE;
+
+ if (strcmp(cmd, "dump") == 0) {
+ if (pmic_dump(p))
+ return CMD_RET_FAILURE;
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "read") == 0) {
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ reg = simple_strtoul(argv[3], NULL, 16);
+ ret = pmic_reg_read(p, reg, &val);
+
+ if (ret)
+ puts("PMIC: Register read failed\n");
+
+ printf("\n0x%02x: 0x%08x\n", reg, val);
+
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "write") == 0) {
+ if (argc < 5)
+ return CMD_RET_USAGE;
+
+ reg = simple_strtoul(argv[3], NULL, 16);
+ val = simple_strtoul(argv[4], NULL, 16);
+ pmic_reg_write(p, reg, val);
+
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(cmd, "bat") == 0) {
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ if (!p->pbat) {
+ printf("%s is not a battery\n", p->name);
+ return CMD_RET_FAILURE;
+ }
+
+ if (strcmp(argv[3], "state") == 0)
+ p->fg->fg_battery_check(p->pbat->fg, p);
+
+ if (strcmp(argv[3], "charge") == 0) {
+ printf("BAT: %s charging (ctrl+c to break)\n",
+ p->name);
+ if (p->low_power_mode)
+ p->low_power_mode();
+ if (p->pbat->battery_charge)
+ p->pbat->battery_charge(p);
+ }
+
+ return CMD_RET_SUCCESS;
+ }
+
+ /* No subcommand found */
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ pmic, CONFIG_SYS_MAXARGS, 1, do_pmic,
+ "PMIC",
+ "list - list available PMICs\n"
+ "pmic name dump - dump named PMIC registers\n"
+ "pmic name read <reg> - read register\n"
+ "pmic name write <reg> <value> - write register\n"
+ "pmic name bat state - write register\n"
+ "pmic name bat charge - write register\n"
+);
diff --git a/qemu/roms/u-boot/drivers/power/power_dialog.c b/qemu/roms/u-boot/drivers/power/power_dialog.c
new file mode 100644
index 000000000..fc95d5a10
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/power_dialog.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <dialog_pmic.h>
+#include <errno.h>
+
+int pmic_dialog_init(unsigned char bus)
+{
+ static const char name[] = "DIALOG_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->number_of_regs = DIALOG_NUM_OF_REGS;
+
+ p->interface = PMIC_I2C;
+ p->hw.i2c.addr = CONFIG_SYS_DIALOG_PMIC_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/power_fsl.c b/qemu/roms/u-boot/drivers/power/power_fsl.c
new file mode 100644
index 000000000..ac0b541d7
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/power_fsl.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <power/pmic.h>
+#include <fsl_pmic.h>
+#include <errno.h>
+
+#if defined(CONFIG_PMIC_FSL_MC13892)
+#define FSL_PMIC_I2C_LENGTH 3
+#elif defined(CONFIG_PMIC_FSL_MC34704)
+#define FSL_PMIC_I2C_LENGTH 1
+#endif
+
+#if defined(CONFIG_POWER_SPI)
+static u32 pmic_spi_prepare_tx(u32 reg, u32 *val, u32 write)
+{
+ return (write << 31) | (reg << 25) | (*val & 0x00FFFFFF);
+}
+#endif
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "FSL_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->bus = bus;
+
+#if defined(CONFIG_POWER_SPI)
+ p->interface = PMIC_SPI;
+ p->hw.spi.cs = CONFIG_FSL_PMIC_CS;
+ p->hw.spi.clk = CONFIG_FSL_PMIC_CLK;
+ p->hw.spi.mode = CONFIG_FSL_PMIC_MODE;
+ p->hw.spi.bitlen = CONFIG_FSL_PMIC_BITLEN;
+ p->hw.spi.flags = SPI_XFER_BEGIN | SPI_XFER_END;
+ p->hw.spi.prepare_tx = pmic_spi_prepare_tx;
+#elif defined(CONFIG_POWER_I2C)
+ p->interface = PMIC_I2C;
+ 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"
+#endif
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/power_i2c.c b/qemu/roms/u-boot/drivers/power/power_i2c.c
new file mode 100644
index 000000000..ac768708e
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/power_i2c.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <power/pmic.h>
+#include <i2c.h>
+#include <compiler.h>
+
+int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
+{
+ unsigned char buf[4] = { 0 };
+
+ if (check_reg(p, reg))
+ return -1;
+
+ switch (pmic_i2c_tx_num) {
+ case 3:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) {
+ buf[2] = (cpu_to_le32(val) >> 16) & 0xff;
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[0] = cpu_to_le32(val) & 0xff;
+ } else {
+ buf[0] = (cpu_to_le32(val) >> 16) & 0xff;
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[2] = cpu_to_le32(val) & 0xff;
+ }
+ break;
+ case 2:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) {
+ buf[1] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[0] = cpu_to_le32(val) & 0xff;
+ } else {
+ buf[0] = (cpu_to_le32(val) >> 8) & 0xff;
+ buf[1] = cpu_to_le32(val) & 0xff;
+ }
+ break;
+ case 1:
+ buf[0] = cpu_to_le32(val) & 0xff;
+ break;
+ default:
+ printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
+ return -1;
+ }
+
+ if (i2c_write(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num))
+ return -1;
+
+ return 0;
+}
+
+int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
+{
+ unsigned char buf[4] = { 0 };
+ u32 ret_val = 0;
+
+ if (check_reg(p, reg))
+ return -1;
+
+ if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num))
+ return -1;
+
+ switch (pmic_i2c_tx_num) {
+ case 3:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG)
+ ret_val = le32_to_cpu(buf[2] << 16
+ | buf[1] << 8 | buf[0]);
+ else
+ ret_val = le32_to_cpu(buf[0] << 16 |
+ buf[1] << 8 | buf[2]);
+ break;
+ case 2:
+ if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG)
+ ret_val = le32_to_cpu(buf[1] << 8 | buf[0]);
+ else
+ ret_val = le32_to_cpu(buf[0] << 8 | buf[1]);
+ break;
+ case 1:
+ ret_val = le32_to_cpu(buf[0]);
+ break;
+ default:
+ printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
+ return -1;
+ }
+ memcpy(val, &ret_val, sizeof(ret_val));
+
+ return 0;
+}
+
+int pmic_probe(struct pmic *p)
+{
+ i2c_set_bus_num(p->bus);
+ debug("Bus: %d PMIC:%s probed!\n", p->bus, p->name);
+ if (i2c_probe(pmic_i2c_addr)) {
+ printf("Can't find PMIC:%s\n", p->name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/power_spi.c b/qemu/roms/u-boot/drivers/power/power_spi.c
new file mode 100644
index 000000000..fb455a006
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/power_spi.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <power/pmic.h>
+#include <spi.h>
+
+static struct spi_slave *slave;
+
+void pmic_spi_free(struct spi_slave *slave)
+{
+ if (slave)
+ spi_free_slave(slave);
+}
+
+struct spi_slave *pmic_spi_probe(struct pmic *p)
+{
+ return spi_setup_slave(p->bus,
+ p->hw.spi.cs,
+ p->hw.spi.clk,
+ p->hw.spi.mode);
+}
+
+static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write)
+{
+ u32 pmic_tx, pmic_rx;
+ u32 tmp;
+
+ if (!slave) {
+ slave = pmic_spi_probe(p);
+
+ if (!slave)
+ return -1;
+ }
+
+ if (check_reg(p, reg))
+ return -1;
+
+ if (spi_claim_bus(slave))
+ return -1;
+
+ pmic_tx = p->hw.spi.prepare_tx(reg, val, write);
+
+ tmp = cpu_to_be32(pmic_tx);
+
+ if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
+ pmic_spi_flags)) {
+ spi_release_bus(slave);
+ return -1;
+ }
+
+ if (write) {
+ pmic_tx = p->hw.spi.prepare_tx(reg, val, 0);
+ tmp = cpu_to_be32(pmic_tx);
+ if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx,
+ pmic_spi_flags)) {
+ spi_release_bus(slave);
+ return -1;
+ }
+ }
+
+ spi_release_bus(slave);
+ *val = cpu_to_be32(pmic_rx);
+
+ return 0;
+}
+
+int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
+{
+ if (pmic_reg(p, reg, &val, 1))
+ return -1;
+
+ return 0;
+}
+
+int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
+{
+ if (pmic_reg(p, reg, val, 0))
+ return -1;
+
+ return 0;
+}
diff --git a/qemu/roms/u-boot/drivers/power/tps6586x.c b/qemu/roms/u-boot/drivers/power/tps6586x.c
new file mode 100644
index 000000000..d29d96953
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/tps6586x.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#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
+static 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;
+}
+
+static 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;
+}
diff --git a/qemu/roms/u-boot/drivers/power/twl4030.c b/qemu/roms/u-boot/drivers/power/twl4030.c
new file mode 100644
index 000000000..3e5031046
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/twl4030.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * twl4030_power_reset_init is derived from code on omapzoom,
+ * git://git.omapzoom.com/repo/u-boot.git
+ *
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ *
+ * twl4030_power_init is from cpu/omap3/common.c, power_init_r
+ *
+ * (C) Copyright 2004-2008
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ * Sunil Kumar <sunilsaini05 at gmail.com>
+ * Shashi Ranjan <shashiranjanmca05 at gmail.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2 at ti.com>
+ * Syed Mohammed Khasim <khasim at ti.com>
+ */
+
+#include <twl4030.h>
+
+/*
+ * Power Reset
+ */
+void twl4030_power_reset_init(void)
+{
+ u8 val = 0;
+ if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, &val)) {
+ printf("Error:TWL4030: failed to read the power register\n");
+ printf("Could not initialize hardware reset\n");
+ } else {
+ val |= TWL4030_PM_MASTER_SW_EVENTS_STOPON_PWRON;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_P1_SW_EVENTS, val)) {
+ printf("Error:TWL4030: failed to write the power register\n");
+ printf("Could not initialize hardware reset\n");
+ }
+ }
+}
+
+/*
+ * Set Device Group and Voltage
+ */
+void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
+ u8 dev_grp, u8 dev_grp_sel)
+{
+ int ret;
+
+ /* Select the Voltage */
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, vsel_reg,
+ vsel_val);
+ if (ret != 0) {
+ printf("Could not write vsel to reg %02x (%d)\n",
+ vsel_reg, ret);
+ return;
+ }
+
+ /* Select the Device Group (enable the supply if dev_grp_sel != 0) */
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, dev_grp,
+ dev_grp_sel);
+ if (ret != 0)
+ printf("Could not write grp_sel to reg %02x (%d)\n",
+ dev_grp, ret);
+}
+
+void twl4030_power_init(void)
+{
+ /* set VAUX3 to 2.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VAUX3_DEDICATED,
+ TWL4030_PM_RECEIVER_VAUX3_VSEL_28,
+ TWL4030_PM_RECEIVER_VAUX3_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+
+ /* set VPLL2 to 1.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VPLL2_DEDICATED,
+ TWL4030_PM_RECEIVER_VPLL2_VSEL_18,
+ TWL4030_PM_RECEIVER_VPLL2_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_ALL);
+
+ /* set VDAC to 1.8V */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VDAC_DEDICATED,
+ TWL4030_PM_RECEIVER_VDAC_VSEL_18,
+ TWL4030_PM_RECEIVER_VDAC_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+}
+
+void twl4030_power_mmc_init(void)
+{
+ /* Set VMMC1 to 3.15 Volts */
+ twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC1_DEDICATED,
+ TWL4030_PM_RECEIVER_VMMC1_VSEL_32,
+ TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
+ TWL4030_PM_RECEIVER_DEV_GRP_P1);
+}
diff --git a/qemu/roms/u-boot/drivers/power/twl6030.c b/qemu/roms/u-boot/drivers/power/twl6030.c
new file mode 100644
index 000000000..a1c6663a2
--- /dev/null
+++ b/qemu/roms/u-boot/drivers/power/twl6030.c
@@ -0,0 +1,235 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <config.h>
+#ifdef CONFIG_TWL6030_POWER
+
+#include <twl6030.h>
+
+static struct twl6030_data *twl;
+
+static struct twl6030_data twl6030_info = {
+ .chip_type = chip_TWL6030,
+ .adc_rbase = GPCH0_LSB,
+ .adc_ctrl = CTRL_P2,
+ .adc_enable = CTRL_P2_SP2,
+ .vbat_mult = TWL6030_VBAT_MULT,
+ .vbat_shift = TWL6030_VBAT_SHIFT,
+};
+
+static struct twl6030_data twl6032_info = {
+ .chip_type = chip_TWL6032,
+ .adc_rbase = TWL6032_GPCH0_LSB,
+ .adc_ctrl = TWL6032_CTRL_P1,
+ .adc_enable = CTRL_P1_SP1,
+ .vbat_mult = TWL6032_VBAT_MULT,
+ .vbat_shift = TWL6032_VBAT_SHIFT,
+};
+
+static int twl6030_gpadc_read_channel(u8 channel_no)
+{
+ u8 lsb = 0;
+ u8 msb = 0;
+ int ret = 0;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_rbase + channel_no * 2, &lsb);
+ if (ret)
+ return ret;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_rbase + 1 + channel_no * 2, &msb);
+ if (ret)
+ return ret;
+
+ return (msb << 8) | lsb;
+}
+
+static int twl6030_gpadc_sw2_trigger(void)
+{
+ u8 val;
+ int ret = 0;
+
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ twl->adc_ctrl, twl->adc_enable);
+ if (ret)
+ return ret;
+
+ /* Waiting until the SW1 conversion ends*/
+ val = CTRL_P2_BUSY;
+
+ while (!((val & CTRL_P2_EOCP2) && (!(val & CTRL_P2_BUSY)))) {
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_ADC,
+ twl->adc_ctrl, &val);
+ if (ret)
+ return ret;
+ udelay(1000);
+ }
+
+ return 0;
+}
+
+void twl6030_stop_usb_charging(void)
+{
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, CONTROLLER_CTRL1, 0);
+
+ return;
+}
+
+void twl6030_start_usb_charging(void)
+{
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_VICHRG, CHARGERUSB_VICHRG_1500);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_CINLIMIT, CHARGERUSB_CIN_LIMIT_NONE);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CONTROLLER_INT_MASK, MBAT_TEMP);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_INT_MASK, MASK_MCHARGERUSB_THMREG);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_VOREG, CHARGERUSB_VOREG_4P0);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CHARGERUSB_CTRL2, CHARGERUSB_CTRL2_VITERM_400);
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, CHARGERUSB_CTRL1, TERM);
+ /* Enable USB charging */
+ twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER,
+ CONTROLLER_CTRL1, CONTROLLER_CTRL1_EN_CHARGER);
+ return;
+}
+
+int twl6030_get_battery_current(void)
+{
+ int battery_current = 0;
+ u8 msb = 0;
+ u8 lsb = 0;
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, FG_REG_11, &msb);
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, FG_REG_10, &lsb);
+ battery_current = ((msb << 8) | lsb);
+
+ /* convert 10 bit signed number to 16 bit signed number */
+ if (battery_current >= 0x2000)
+ battery_current = (battery_current - 0x4000);
+
+ battery_current = battery_current * 3000 / 4096;
+ printf("Battery Current: %d mA\n", battery_current);
+
+ return battery_current;
+}
+
+int twl6030_get_battery_voltage(void)
+{
+ int battery_volt = 0;
+ int ret = 0;
+ u8 vbatch;
+
+ if (twl->chip_type == chip_TWL6030) {
+ vbatch = TWL6030_GPADC_VBAT_CHNL;
+ } else {
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6032_GPSELECT_ISB,
+ TWL6032_GPADC_VBAT_CHNL);
+ if (ret)
+ return ret;
+ vbatch = 0;
+ }
+
+ /* Start GPADC SW conversion */
+ ret = twl6030_gpadc_sw2_trigger();
+ if (ret) {
+ printf("Failed to convert battery voltage\n");
+ return ret;
+ }
+
+ /* measure Vbat voltage */
+ battery_volt = twl6030_gpadc_read_channel(vbatch);
+ if (battery_volt < 0) {
+ printf("Failed to read battery voltage\n");
+ return ret;
+ }
+ battery_volt = (battery_volt * twl->vbat_mult) >> twl->vbat_shift;
+ printf("Battery Voltage: %d mV\n", battery_volt);
+
+ return battery_volt;
+}
+
+void twl6030_init_battery_charging(void)
+{
+ u8 val = 0;
+ int battery_volt = 0;
+ int ret = 0;
+
+ ret = twl6030_i2c_read_u8(TWL6030_CHIP_USB, USB_PRODUCT_ID_LSB, &val);
+ if (ret) {
+ puts("twl6030_init_battery_charging(): could not determine chip!\n");
+ return;
+ }
+ if (val == 0x30) {
+ twl = &twl6030_info;
+ } else if (val == 0x32) {
+ twl = &twl6032_info;
+ } else {
+ puts("twl6030_init_battery_charging(): unsupported chip type\n");
+ return;
+ }
+
+ /* Enable VBAT measurement */
+ if (twl->chip_type == chip_TWL6030) {
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, MISC1, VBAT_MEAS);
+ twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6030_GPADC_CTRL,
+ GPADC_CTRL_SCALER_DIV4);
+ } else {
+ twl6030_i2c_write_u8(TWL6030_CHIP_ADC,
+ TWL6032_GPADC_CTRL2,
+ GPADC_CTRL2_CH18_SCALER_EN);
+ }
+
+ /* Enable GPADC module */
+ ret = twl6030_i2c_write_u8(TWL6030_CHIP_CHARGER, TOGGLE1, FGS | GPADCS);
+ if (ret) {
+ printf("Failed to enable GPADC\n");
+ return;
+ }
+
+ battery_volt = twl6030_get_battery_voltage();
+ if (battery_volt < 0)
+ return;
+
+ if (battery_volt < 3000)
+ printf("Main battery voltage too low!\n");
+
+ /* Check for the presence of USB charger */
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, CONTROLLER_STAT1, &val);
+
+ /* check for battery presence indirectly via Fuel gauge */
+ if ((val & VBUS_DET) && (battery_volt < 3300))
+ twl6030_start_usb_charging();
+
+ return;
+}
+
+void twl6030_power_mmc_init()
+{
+ /* set voltage to 3.0 and turnon for APP */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, VMMC_CFG_VOLTATE, 0x15);
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, VMMC_CFG_STATE, 0x21);
+}
+
+void twl6030_usb_device_settings()
+{
+ u8 data = 0;
+
+ /* Select APP Group and set state to ON */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, VUSB_CFG_STATE, 0x21);
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_PM, MISC2, &data);
+ data |= 0x10;
+
+ /* Select the input supply for VBUS regulator */
+ twl6030_i2c_write_u8(TWL6030_CHIP_PM, MISC2, data);
+}
+#endif