linux/arch/arm/mach-davinci/pm.c
<<
>>
Prefs
   1/*
   2 * DaVinci Power Management Routines
   3 *
   4 * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/pm.h>
  12#include <linux/suspend.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/clk.h>
  16#include <linux/spinlock.h>
  17
  18#include <asm/cacheflush.h>
  19#include <asm/delay.h>
  20#include <asm/io.h>
  21
  22#include <mach/common.h>
  23#include <mach/da8xx.h>
  24#include <mach/sram.h>
  25#include <mach/pm.h>
  26
  27#include "clock.h"
  28
  29#define DEEPSLEEP_SLEEPCOUNT_MASK       0xFFFF
  30
  31static void (*davinci_sram_suspend) (struct davinci_pm_config *);
  32static struct davinci_pm_config *pdata;
  33
  34static void davinci_sram_push(void *dest, void *src, unsigned int size)
  35{
  36        memcpy(dest, src, size);
  37        flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
  38}
  39
  40static void davinci_pm_suspend(void)
  41{
  42        unsigned val;
  43
  44        if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
  45
  46                /* Switch CPU PLL to bypass mode */
  47                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  48                val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
  49                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  50
  51                udelay(PLL_BYPASS_TIME);
  52
  53                /* Powerdown CPU PLL */
  54                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  55                val |= PLLCTL_PLLPWRDN;
  56                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  57        }
  58
  59        /* Configure sleep count in deep sleep register */
  60        val = __raw_readl(pdata->deepsleep_reg);
  61        val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
  62        val |= pdata->sleepcount;
  63        __raw_writel(val, pdata->deepsleep_reg);
  64
  65        /* System goes to sleep in this call */
  66        davinci_sram_suspend(pdata);
  67
  68        if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
  69
  70                /* put CPU PLL in reset */
  71                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  72                val &= ~PLLCTL_PLLRST;
  73                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  74
  75                /* put CPU PLL in power down */
  76                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  77                val &= ~PLLCTL_PLLPWRDN;
  78                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  79
  80                /* wait for CPU PLL reset */
  81                udelay(PLL_RESET_TIME);
  82
  83                /* bring CPU PLL out of reset */
  84                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  85                val |= PLLCTL_PLLRST;
  86                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  87
  88                /* Wait for CPU PLL to lock */
  89                udelay(PLL_LOCK_TIME);
  90
  91                /* Remove CPU PLL from bypass mode */
  92                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  93                val &= ~PLLCTL_PLLENSRC;
  94                val |= PLLCTL_PLLEN;
  95                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  96        }
  97}
  98
  99static int davinci_pm_enter(suspend_state_t state)
 100{
 101        int ret = 0;
 102
 103        switch (state) {
 104        case PM_SUSPEND_STANDBY:
 105        case PM_SUSPEND_MEM:
 106                davinci_pm_suspend();
 107                break;
 108        default:
 109                ret = -EINVAL;
 110        }
 111
 112        return ret;
 113}
 114
 115static const struct platform_suspend_ops davinci_pm_ops = {
 116        .enter          = davinci_pm_enter,
 117        .valid          = suspend_valid_only_mem,
 118};
 119
 120static int __init davinci_pm_probe(struct platform_device *pdev)
 121{
 122        pdata = pdev->dev.platform_data;
 123        if (!pdata) {
 124                dev_err(&pdev->dev, "cannot get platform data\n");
 125                return -ENOENT;
 126        }
 127
 128        davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
 129        if (!davinci_sram_suspend) {
 130                dev_err(&pdev->dev, "cannot allocate SRAM memory\n");
 131                return -ENOMEM;
 132        }
 133
 134        davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
 135                                                davinci_cpu_suspend_sz);
 136
 137        suspend_set_ops(&davinci_pm_ops);
 138
 139        return 0;
 140}
 141
 142static int __exit davinci_pm_remove(struct platform_device *pdev)
 143{
 144        sram_free(davinci_sram_suspend, davinci_cpu_suspend_sz);
 145        return 0;
 146}
 147
 148static struct platform_driver davinci_pm_driver = {
 149        .driver = {
 150                .name    = "pm-davinci",
 151                .owner   = THIS_MODULE,
 152        },
 153        .remove = __exit_p(davinci_pm_remove),
 154};
 155
 156int __init davinci_pm_init(void)
 157{
 158        return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
 159}
 160