mirror_ubuntu-kernels/arch/arm/mach-davinci/pm.c
Kevin Hilman aa9aa1ec2d ARM: davinci: PM: rework init, remove platform device
Remove fake platform device used for PM init.  Move pdata values which
are common across all current platforms into pm.c.

Also, since PM is only used on da8xx, remove davinci_pm_init() from
common init code, and only use in da850/omapl138 board files that are
currently creating the fake platform_device.

Suggested-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
[nsekhar@ti.com: subject line adjustment]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
2016-11-16 14:41:29 +05:30

173 lines
4.1 KiB
C

/*
* DaVinci Power Management Routines
*
* Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
*
* 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.
*/
#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <asm/cacheflush.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <mach/common.h>
#include <mach/da8xx.h>
#include <mach/mux.h>
#include <mach/pm.h>
#include "clock.h"
#include "psc.h"
#include "sram.h"
#define DA850_PLL1_BASE 0x01e1a000
#define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF
#define DEEPSLEEP_SLEEPCOUNT 128
static void (*davinci_sram_suspend) (struct davinci_pm_config *);
static struct davinci_pm_config pm_config = {
.sleepcount = DEEPSLEEP_SLEEPCOUNT,
.ddrpsc_num = DA8XX_LPSC1_EMIF3C,
};
static struct davinci_pm_config *pdata = &pm_config;
static void davinci_sram_push(void *dest, void *src, unsigned int size)
{
memcpy(dest, src, size);
flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
}
static void davinci_pm_suspend(void)
{
unsigned val;
if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
/* Switch CPU PLL to bypass mode */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
udelay(PLL_BYPASS_TIME);
/* Powerdown CPU PLL */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val |= PLLCTL_PLLPWRDN;
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
}
/* Configure sleep count in deep sleep register */
val = __raw_readl(pdata->deepsleep_reg);
val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
val |= pdata->sleepcount;
__raw_writel(val, pdata->deepsleep_reg);
/* System goes to sleep in this call */
davinci_sram_suspend(pdata);
if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
/* put CPU PLL in reset */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val &= ~PLLCTL_PLLRST;
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
/* put CPU PLL in power down */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val &= ~PLLCTL_PLLPWRDN;
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
/* wait for CPU PLL reset */
udelay(PLL_RESET_TIME);
/* bring CPU PLL out of reset */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val |= PLLCTL_PLLRST;
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
/* Wait for CPU PLL to lock */
udelay(PLL_LOCK_TIME);
/* Remove CPU PLL from bypass mode */
val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
val &= ~PLLCTL_PLLENSRC;
val |= PLLCTL_PLLEN;
__raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
}
}
static int davinci_pm_enter(suspend_state_t state)
{
int ret = 0;
switch (state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
davinci_pm_suspend();
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct platform_suspend_ops davinci_pm_ops = {
.enter = davinci_pm_enter,
.valid = suspend_valid_only_mem,
};
int __init davinci_pm_init(void)
{
int ret;
ret = davinci_cfg_reg(DA850_RTC_ALARM);
if (ret)
return ret;
pdata->ddr2_ctlr_base = da8xx_get_mem_ctlr();
pdata->deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG);
pdata->cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K);
if (!pdata->cpupll_reg_base)
return -ENOMEM;
pdata->ddrpll_reg_base = ioremap(DA850_PLL1_BASE, SZ_4K);
if (!pdata->ddrpll_reg_base) {
ret = -ENOMEM;
goto no_ddrpll_mem;
}
pdata->ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K);
if (!pdata->ddrpsc_reg_base) {
ret = -ENOMEM;
goto no_ddrpsc_mem;
}
davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
if (!davinci_sram_suspend) {
pr_err("PM: cannot allocate SRAM memory\n");
return -ENOMEM;
}
davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
davinci_cpu_suspend_sz);
suspend_set_ops(&davinci_pm_ops);
no_ddrpsc_mem:
iounmap(pdata->ddrpll_reg_base);
no_ddrpll_mem:
iounmap(pdata->cpupll_reg_base);
return ret;
}