power: charge animation: support auto wakeup and auto off screen

Change-Id: I93f97c46e5f08c3ebe4b577355f5e23a9e3659ed
Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
Joseph Chen 2018-03-13 19:57:46 +08:00 committed by Kever Yang
parent 616056c90c
commit e7f9facb5d
2 changed files with 89 additions and 2 deletions

View File

@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/io.h>
#include <common.h>
#include <boot_rkimg.h>
#include <console.h>
@ -22,6 +23,7 @@
#include <power/pmic.h>
#include <power/rk8xx_pmic.h>
#include <power/regulator.h>
#include <rk_timer_irq.h>
#include <video_rockchip.h>
DECLARE_GLOBAL_DATA_PTR;
@ -39,6 +41,9 @@ struct charge_animation_priv {
struct udevice *fg;
const struct charge_image *image;
int image_num;
int auto_wakeup_key_state;
ulong auto_screen_off_timeout;
};
/*
@ -80,6 +85,14 @@ static int charge_animation_ofdata_to_platdata(struct udevice *dev)
pdata->system_suspend =
dev_read_u32_default(dev, "rockchip,system-suspend", 0);
pdata->auto_wakeup_interval =
dev_read_u32_default(dev, "rockchip,auto-wakeup-interval", 0);
pdata->auto_wakeup_screen_invert =
dev_read_u32_default(dev, "rockchip,auto-wakeup-screen-invert", 0);
pdata->auto_off_screen_interval =
dev_read_u32_default(dev, "rockchip,auto-off-screen-interval", 15);
if (pdata->screen_on_voltage > pdata->exit_charge_voltage)
pdata->screen_on_voltage = pdata->exit_charge_voltage;
@ -92,14 +105,33 @@ static int charge_animation_ofdata_to_platdata(struct udevice *dev)
return 0;
}
static int check_key_press(void)
static int check_key_press(struct udevice *dev)
{
struct charge_animation_pdata *pdata = dev_get_platdata(dev);
struct charge_animation_priv *priv = dev_get_priv(dev);
u32 state;
state = platform_key_read(KEY_POWER);
if (state < 0)
printf("read power key failed: %d\n", state);
/* Fixup key state for following cases */
if (pdata->auto_wakeup_interval) {
if (pdata->auto_wakeup_screen_invert) {
if (priv->auto_wakeup_key_state == KEY_PRESS_DOWN) {
/* Value is updated in timer interrupt */
priv->auto_wakeup_key_state = KEY_PRESS_NONE;
state = KEY_PRESS_DOWN;
}
}
} else if (pdata->auto_off_screen_interval) {
if (get_timer(priv->auto_screen_off_timeout) >
pdata->auto_off_screen_interval * 1000) { /* 1000ms */
state = KEY_PRESS_DOWN;
printf("Auto screen off\n");
}
}
return state;
}
@ -217,6 +249,42 @@ static int charge_extrem_low_power(struct udevice *dev)
return 0;
}
static void timer_irq_handler(int irq, void *data)
{
struct udevice *dev = data;
struct charge_animation_priv *priv = dev_get_priv(dev);
static long long count;
writel(TIMER_CLR_INT, TIMER_BASE + TIMER_INTSTATUS);
priv->auto_wakeup_key_state = KEY_PRESS_DOWN;
printf("auto wakeup count: %lld\n", ++count);
}
static void autowakeup_timer_init(struct udevice *dev)
{
struct charge_animation_pdata *pdata = dev_get_platdata(dev);
uint64_t period = 24000000ULL * (pdata->auto_wakeup_interval);
/* Disable before conifg */
writel(0, TIMER_BASE + TIMER_CTRL);
/* Config */
writel((uint32_t)period, TIMER_BASE + TIMER_LOAD_COUNT0);
writel((uint32_t)(period >> 32), TIMER_BASE + TIMER_LOAD_COUNT1);
writel(TIMER_CLR_INT, TIMER_BASE + TIMER_INTSTATUS);
writel(TIMER_EN | TIMER_INT_EN, TIMER_BASE + TIMER_CTRL);
/* IRQ */
irq_install_handler(TIMER_IRQ, timer_irq_handler, dev);
irq_handler_enable(TIMER_IRQ);
}
static void autowakeup_timer_uninit(void)
{
irq_free_handler(TIMER_IRQ);
}
static int charge_animation_show(struct udevice *dev)
{
struct charge_animation_pdata *pdata = dev_get_platdata(dev);
@ -297,9 +365,16 @@ static int charge_animation_show(struct udevice *dev)
charge_show_bmp(NULL);
}
/* Auto wakeup */
if (pdata->auto_wakeup_interval) {
printf("Auto wakeup: %dS\n", pdata->auto_wakeup_interval);
autowakeup_timer_init(dev);
}
printf("Enter U-Boot charging mode\n");
charge_start = get_timer(0);
/* Charging ! */
while (1) {
debug("step1 (%d)... \n", screen_on);
@ -409,7 +484,13 @@ static int charge_animation_show(struct udevice *dev)
if (screen_on) {
debug("SHOW: %s\n", image[show_idx].name);
charge_show_bmp(image[show_idx].name);
/* Re calculate timeout to off screen */
if (priv->auto_screen_off_timeout == 0)
priv->auto_screen_off_timeout = get_timer(0);
} else {
priv->auto_screen_off_timeout = 0;
system_suspend_enter(pdata);
}
@ -432,7 +513,7 @@ static int charge_animation_show(struct udevice *dev)
* Short key event: turn on/off screen;
* Long key event: show logo and boot system or still charging.
*/
key_state = check_key_press();
key_state = check_key_press(dev);
if (key_state == KEY_PRESS_DOWN) {
/* NULL means show nothing, ie. turn off screen */
if (screen_on)
@ -499,6 +580,9 @@ static int charge_animation_show(struct udevice *dev)
}
}
if (pdata->auto_wakeup_interval)
autowakeup_timer_uninit();
ms = get_timer(charge_start);
if (ms >= 1000) {
sec = ms / 1000;

View File

@ -17,6 +17,9 @@ struct charge_animation_pdata {
int screen_on_voltage;
int system_suspend;
int auto_wakeup_interval;
int auto_wakeup_screen_invert;
int auto_off_screen_interval;
};
#endif