From 6e9c5267abb0f4a5a5f3ba2a32492555c4d06361 Mon Sep 17 00:00:00 2001
From: Przemyslaw Marczak
Date: Mon, 24 Mar 2014 10:40:12 +0100
Subject: [PATCH] trats2: add support to interactive charger
This commit adds support to interactive charger api which means an
implementation of listed functions:
- charger_enable() - enable the charger.Charger can be enabled
automatically if the device power on state
is triggered by USB cable connection.
- charger_type() - this function returns device type connected
to usb port of device. For charger api matters
only positive value.
- battery_present() - check if battery is connected (DETBAT pin)
- battery_state() - check battery charge level. Returns percent value.
- low_power_mode() - switch SOC into low power mode which covers:
- disable cores: 1, 2, 3,
- disable SOC unused power domains,
- decrease CPU clock to 200 MHz
After low_power_mode() function call, device should be restarted,
which is implemented in interactive charger.
Change-Id: I7e664fab29c45c2d29dc57a2faa887d88530d8f3
Signed-off-by: Przemyslaw Marczak
---
board/samsung/trats2/trats2.c | 251 +++++++++++++++++++++++++++++++++++++++---
include/configs/trats2.h | 3 +
2 files changed, 236 insertions(+), 18 deletions(-)
diff --git a/board/samsung/trats2/trats2.c b/board/samsung/trats2/trats2.c
index 13f5d88..945188f 100644
--- a/board/samsung/trats2/trats2.c
+++ b/board/samsung/trats2/trats2.c
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -18,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -25,8 +27,12 @@
DECLARE_GLOBAL_DATA_PTR;
-static unsigned int board_rev = -1;
+/* For global battery and charger functions */
+static struct power_battery *pbat;
+static struct pmic *p_chrg, *p_muic, *p_fg, *p_bat;
+static int power_init_done;
+static unsigned int board_rev = -1;
static inline u32 get_model_rev(void);
static void check_hw_revision(void)
@@ -161,10 +167,6 @@ int exynos_init(void)
int exynos_power_init(void)
{
- int chrg;
- struct power_battery *pb;
- struct pmic *p_chrg, *p_muic, *p_fg, *p_bat;
-
#ifdef CONFIG_SYS_I2C_INIT_BOARD
board_init_i2c();
#endif
@@ -206,21 +208,13 @@ int exynos_power_init(void)
p_chrg->parent = p_bat;
p_muic->parent = p_bat;
+#ifdef CONFIG_INTERACTIVE_CHARGER
+ p_bat->low_power_mode = board_low_power_mode;
+#endif
p_bat->pbat->battery_init(p_bat, p_fg, p_chrg, p_muic);
- pb = p_bat->pbat;
- chrg = p_muic->chrg->chrg_type(p_muic);
- debug("CHARGER TYPE: %d\n", chrg);
-
- if (!p_chrg->chrg->chrg_bat_present(p_chrg)) {
- puts("No battery detected\n");
- return 0;
- }
-
- p_fg->fg->fg_battery_check(p_fg, p_bat);
-
- if (pb->bat->state == CHARGE && chrg == CHARGER_USB)
- puts("CHARGE Battery !\n");
+ pbat = p_bat->pbat;
+ power_init_done = 1;
return 0;
}
@@ -415,6 +409,131 @@ void exynos_lcd_misc_init(vidinfo_t *vid)
}
#endif /* LCD */
+void low_clock_mode(void)
+{
+ struct exynos4x12_clock *clk = (struct exynos4x12_clock *)
+ samsung_get_base_clock();
+
+ unsigned int cfg_apll_con0;
+ unsigned int cfg_src_cpu;
+ unsigned int cfg_div_cpu0;
+ unsigned int cfg_div_cpu1;
+ unsigned int clk_gate_cfg;
+
+ /* Turn off unnecessary clocks */
+ clk_gate_cfg = 0x0;
+ writel(clk_gate_cfg, &clk->gate_ip_image); /* IMAGE */
+ writel(clk_gate_cfg, &clk->gate_ip_cam); /* CAM */
+ writel(clk_gate_cfg, &clk->gate_ip_tv); /* TV */
+ writel(clk_gate_cfg, &clk->gate_ip_mfc); /* MFC */
+ writel(clk_gate_cfg, &clk->gate_ip_g3d); /* G3D */
+ writel(clk_gate_cfg, &clk->gate_ip_gps); /* GPS */
+ writel(clk_gate_cfg, &clk->gate_ip_isp1); /* ISP1 */
+
+ /*
+ * Set CMU_CPU clocks src to MPLL
+ * Bit values: 0 ; 1
+ * MUX_APLL_SEL: FIN_PLL; FOUT_APLL
+ * MUX_CORE_SEL: MOUT_APLL; SCLK_MPLL
+ * MUX_HPM_SEL: MOUT_APLL; SCLK_MPLL_USER_C
+ * MUX_MPLL_USER_SEL_C: FIN_PLL; SCLK_MPLL
+ */
+ cfg_src_cpu = MUX_APLL_SEL(1) | MUX_CORE_SEL(1) | MUX_HPM_SEL(1) |
+ MUX_MPLL_USER_SEL_C(1);
+ writel(cfg_src_cpu, &clk->src_cpu);
+
+ /* Disable APLL */
+ cfg_apll_con0 = readl(&clk->apll_con0);
+ writel(cfg_apll_con0 & ~PLL_ENABLE(1), &clk->apll_con0);
+
+ /* Set APLL to 200MHz */
+ cfg_apll_con0 = SDIV(2) | PDIV(3) | MDIV(100) | FSEL(1) | PLL_ENABLE(1);
+ writel(cfg_apll_con0, &clk->apll_con0);
+
+ /* Wait for PLL to be locked */
+ while (!(readl(&clk->apll_con0) & PLL_LOCKED_BIT))
+ continue;
+
+ /* Set CMU_CPU clock src to APLL */
+ cfg_src_cpu = MUX_APLL_SEL(1) | MUX_CORE_SEL(0) | MUX_HPM_SEL(0) |
+ MUX_MPLL_USER_SEL_C(0);
+ writel(cfg_src_cpu, &clk->src_cpu);
+
+ /* Wait for MUX ready status */
+ while (readl(&clk->src_cpu) & MUX_STAT_CPU_CHANGING)
+ continue;
+
+ /*
+ * Set dividers for MOUTcore = 200 MHz
+ * coreout = MOUT / (ratio + 1) = 200 MHz
+ * corem0 = armclk / (ratio + 1) = 200 MHz
+ * corem1 = armclk / (ratio + 1) = 200 MHz
+ * periph = armclk / (ratio + 1) = 200 MHz
+ * atbout = MOUT / (ratio + 1) = 200 MHz
+ * pclkdbgout = atbout / (ratio + 1) = 200 MHz
+ * sclkapll = MOUTapll / (ratio + 1) = 50 MHz
+ * armclk = core_out / (ratio + 1) = 200 MHz
+ */
+ cfg_div_cpu0 = CORE_RATIO(0) | COREM0_RATIO(0) | COREM1_RATIO(0) |
+ PERIPH_RATIO(0) | ATB_RATIO(0) | PCLK_DBG_RATIO(1) |
+ APLL_RATIO(3) | CORE2_RATIO(0);
+ writel(cfg_div_cpu0, &clk->div_cpu0);
+
+ /* Wait for divider ready status */
+ while (readl(&clk->div_stat_cpu0) & DIV_STAT_CPU0_CHANGING)
+ continue;
+
+ /*
+ * For MOUThpm = 200 MHz (MOUTapll)
+ * doutcopy = MOUThpm / (ratio + 1) = 100
+ * sclkhpm = doutcopy / (ratio + 1) = 100
+ * cores_out = armclk / (ratio + 1) = 200
+ */
+ cfg_div_cpu1 = COPY_RATIO(1) | HPM_RATIO(0) | CORES_RATIO(0);
+ writel(cfg_div_cpu1, &clk->div_cpu1); /* DIV_CPU1 */
+
+ /* Wait for divider ready status */
+ while (readl(&clk->div_stat_cpu1) & DIV_STAT_CPU1_CHANGING)
+ continue;
+}
+
+#ifdef CONFIG_INTERACTIVE_CHARGER
+static int low_power_mode_set;
+
+void board_low_power_mode(void)
+{
+ struct exynos4x12_power *pwr = (struct exynos4x12_power *)
+ samsung_get_base_power();
+
+ unsigned int pwr_core_cfg = 0x0;
+ unsigned int pwr_cfg = 0x0;
+
+ /* Set low power mode only once */
+ if (low_power_mode_set)
+ return;
+
+ /* Power down CORES: 1, 2, 3 */
+ /* LOCAL_PWR_CFG [1:0] 0x3 EN, 0x0 DIS */
+ writel(pwr_core_cfg, &pwr->arm_core1_configuration);
+ writel(pwr_core_cfg, &pwr->arm_core2_configuration);
+ writel(pwr_core_cfg, &pwr->arm_core3_configuration);
+
+ /* Turn off unnecessary power domains */
+ writel(pwr_cfg, &pwr->xxti_configuration); /* XXTI */
+ writel(pwr_cfg, &pwr->cam_configuration); /* CAM */
+ writel(pwr_cfg, &pwr->tv_configuration); /* TV */
+ writel(pwr_cfg, &pwr->mfc_configuration); /* MFC */
+ writel(pwr_cfg, &pwr->g3d_configuration); /* G3D */
+ writel(pwr_cfg, &pwr->gps_configuration); /* GPS */
+ writel(pwr_cfg, &pwr->gps_alive_configuration); /* GPS_ALIVE */
+
+ /* Set CPU clock to 200MHz */
+ low_clock_mode();
+
+ low_power_mode_set = 1;
+}
+#endif
+
#ifdef CONFIG_CMD_POWEROFF
void board_poweroff(void)
{
@@ -431,3 +550,99 @@ void board_poweroff(void)
/* Should not reach here */
}
#endif
+
+/* Functions for interactive charger in board/samsung/common/misc.c */
+#ifdef CONFIG_INTERACTIVE_CHARGER
+int charger_enable(void)
+{
+ if (!power_init_done) {
+ if (exynos_power_init()) {
+ puts("Can't init board power subsystem");
+ return -1;
+ }
+ }
+
+ if (!pbat->battery_charge) {
+ puts("Can't enable charger\n");
+ return -1;
+ }
+
+ /* Enable charger */
+ if (pbat->battery_charge(p_bat)) {
+ puts("Charger enable error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int charger_type(void)
+{
+ if (!power_init_done) {
+ if (exynos_power_init()) {
+ puts("Can't init board power subsystem");
+ return -1;
+ }
+ }
+
+ if (!p_muic->chrg->chrg_type) {
+ puts("Can't get charger type\n");
+ return -1;
+ }
+
+ return p_muic->chrg->chrg_type(p_muic);
+}
+
+int battery_present(void)
+{
+ if (!power_init_done) {
+ if (exynos_power_init()) {
+ puts("Can't init board power subsystem");
+ return -1;
+ }
+ }
+
+ if (!p_chrg->chrg->chrg_bat_present) {
+ puts("Can't get battery state\n");
+ return -1;
+ }
+
+ if (!p_chrg->chrg->chrg_bat_present(p_chrg)) {
+ puts("Battery not present.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+int battery_state(unsigned int *soc)
+{
+ struct battery *bat = pbat->bat;
+
+ if (!power_init_done) {
+ if (exynos_power_init()) {
+ printf("Can't init board power subsystem");
+ return -1;
+ }
+ }
+
+ if (!p_fg->fg->fg_battery_update) {
+ puts("Can't update battery state\n");
+ return -1;
+ }
+
+ /* Check battery state */
+ if (p_fg->fg->fg_battery_update(p_fg, p_bat)) {
+ puts("Battery update error\n");
+ return -1;
+ }
+
+ debug("[BAT]:\n#state:%u\n#soc:%3.1u\n#vcell:%u\n", bat->state,
+ bat->state_of_chrg,
+ bat->voltage_uV);
+
+ *soc = bat->state_of_chrg;
+
+ return 0;
+}
+#endif
diff --git a/include/configs/trats2.h b/include/configs/trats2.h
index f8ca576..d348d78 100644
--- a/include/configs/trats2.h
+++ b/include/configs/trats2.h
@@ -209,6 +209,9 @@ int get_soft_i2c_sda_pin(void);
#define CONFIG_MISC_INIT_R
+/* Charge battery with interactive LCD animation */
+#define CONFIG_INTERACTIVE_CHARGER
+
/* Download menu - Samsung common */
#define CONFIG_LCD_MENU
#define CONFIG_LCD_MENU_BOARD
--
2.7.4