blob: d1c84edcc57e210605dae06bf732de8b6c8b6dd2 [file] [log] [blame]
/*
* Routines for PMU/Hi6421 suspend/resume. Hi4511 board specific.
*
* Copyright © 2011-2013 HiSilicon Technologies Co., Ltd.
* http://www.hisilicon.com
* Copyright © 2012-2013 Linaro Ltd.
* http://www.linaro.org
*
* Author: Guodong Xu <guodong.xu@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Note: Routines defined in this file is for Hi4511 board specific, and will be
* called during system suspend to RAM. It should be finally moved to Hi6421
* driver's pm routines.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/console.h>
#include <asm/hardware/arm_timer.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include "core.h"
/* function: pmuspi_enable
* description:
* enable pmu clk.
*/
static void pmuspi_enable(void)
{
/*set clk div*/
writel(0xFF0003, (hs_pctrl_va_base + 0x8));
/*enable clk*/
writel(1<<1, (hs_sctrl_base + 0x40));
/*undo reset*/
writel(1<<1, (hs_sctrl_base + 0x9C));
}
/* function: pmuspi_disable
* description:
* disable pmu clk.
*/
static void pmuspi_disable(void)
{
/*reset*/
writel(1<<1, (hs_sctrl_base + 0x98));
/*disable clk*/
writel(1<<1, (hs_sctrl_base + 0x44));
}
#define PMUSPI_REG(x) (hs_pmuspi_va_base + ((x)<<2))
struct pmuregs {
unsigned char ucoffset;
char cval;
char old_val;
char cmask;
};
#define PMU_LOW(x, y, z) { .ucoffset = (x),\
.cval = (y), \
.cmask = (z), \
.old_val = 0, \
}
static struct pmuregs pmuregs_lookups[] = {
/*close LDO0 */
PMU_LOW(0x20, 0x00, 0x10),
/*w 35 0, emmc rst2_n output low.*/
PMU_LOW(0x35, 0x00, 0x01),
/*close ldo13*/
PMU_LOW(0x2D, 0x30, 0x30),
/*w 25 31 LDO5 ECO mode*/
/*PMU_LOW(0x25, 0x20, 0x20),*/
/*w 26 34 LDO6 ECO mode*/
/*PMU_LOW(0x26, 0x20, 0x20),*/
/*w 4e 20 close over temperature protect*/
PMU_LOW(0x4E, 0x00, 0x01),
/*w 52 00 close backup battery charging*/
PMU_LOW(0x52, 0x00, 0x01),
/*w 14 11 BUCK4 Sleep*/
PMU_LOW(0x14, 0x11, 0x11),
/*w 16 11 BUCK5 Sleep*/
PMU_LOW(0x16, 0x11, 0x11),
/*w 8f 08 sleep*/
/*PMU_LOW(0x8F, 0x08, 0x07),*/
};
/* function: pmulowpower
* description:
* configure pmu low power state.
*/
void pmulowpower(int isuspend)
{
int i = 0;
int ilen = ARRAY_SIZE(pmuregs_lookups);
unsigned uregv = 0;
pr_info("[%s] %d enter.\n", __func__, __LINE__);
pmuspi_enable();
if (1 == isuspend) {
for (i = 0; i < ilen; i++) {
uregv = readl(PMUSPI_REG(pmuregs_lookups[i].ucoffset));
pmuregs_lookups[i].old_val = uregv;
uregv &= ~pmuregs_lookups[i].cmask;
uregv |= pmuregs_lookups[i].cval;
writel(uregv, PMUSPI_REG(pmuregs_lookups[i].ucoffset));
}
} else {
for (i = (ilen - 1); i >= 0; i--) {
uregv = readl(PMUSPI_REG(pmuregs_lookups[i].ucoffset));
uregv &= ~pmuregs_lookups[i].cmask;
uregv |= pmuregs_lookups[i].old_val;
writel(uregv, PMUSPI_REG(pmuregs_lookups[i].ucoffset));
}
}
if (1 == isuspend) {
pmuspi_disable();
/* here is an workround way to delay 40ms
* make sure LDO0 is poweroff very clean
*/
mdelay(40);
}
}