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
  21#include <mach/da8xx.h>
  22#include <mach/sram.h>
  23#include <mach/pm.h>
  24
  25#include "clock.h"
  26
  27#define DEEPSLEEP_SLEEPCOUNT_MASK       0xFFFF
  28
  29static void (*davinci_sram_suspend) (struct davinci_pm_config *);
  30static struct davinci_pm_config *pdata;
  31
  32static void davinci_sram_push(void *dest, void *src, unsigned int size)
  33{
  34        memcpy(dest, src, size);
  35        flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
  36}
  37
  38static void davinci_pm_suspend(void)
  39{
  40        unsigned val;
  41
  42        if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
  43
  44                /* Switch CPU PLL to bypass mode */
  45                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  46                val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
  47                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  48
  49                udelay(PLL_BYPASS_TIME);
  50
  51                /* Powerdown CPU PLL */
  52                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  53                val |= PLLCTL_PLLPWRDN;
  54                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  55        }
  56
  57        /* Configure sleep count in deep sleep register */
  58        val = __raw_readl(pdata->deepsleep_reg);
  59        val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
  60        val |= pdata->sleepcount;
  61        __raw_writel(val, pdata->deepsleep_reg);
  62
  63        /* System goes to sleep in this call */
  64        davinci_sram_suspend(pdata);
  65
  66        if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
  67
  68                /* put CPU PLL in reset */
  69                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  70                val &= ~PLLCTL_PLLRST;
  71                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  72
  73                /* put CPU PLL in power down */
  74                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  75                val &= ~PLLCTL_PLLPWRDN;
  76                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  77
  78                /* wait for CPU PLL reset */
  79                udelay(PLL_RESET_TIME);
  80
  81                /* bring CPU PLL out of reset */
  82                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  83                val |= PLLCTL_PLLRST;
  84                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  85
  86                /* Wait for CPU PLL to lock */
  87                udelay(PLL_LOCK_TIME);
  88
  89                /* Remove CPU PLL from bypass mode */
  90                val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
  91                val &= ~PLLCTL_PLLENSRC;
  92                val |= PLLCTL_PLLEN;
  93                __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
  94        }
  95}
  96
  97static int davinci_pm_enter(suspend_state_t state)
  98{
  99        int ret = 0;
 100
 101        switch (state) {
 102        case PM_SUSPEND_STANDBY:
 103        case PM_SUSPEND_MEM:
 104                davinci_pm_suspend();
 105                break;
 106        default:
 107                ret = -EINVAL;
 108        }
 109
 110        return ret;
 111}
 112
 113static const struct platform_suspend_ops davinci_pm_ops = {
 114        .enter          = davinci_pm_enter,
 115        .valid          = suspend_valid_only_mem,
 116};
 117
 118static int __init davinci_pm_probe(struct platform_device *pdev)
 119{
 120        pdata = pdev->dev.platform_data;
 121        if (!pdata) {
 122                dev_err(&pdev->dev, "cannot get platform data\n");
 123                return -ENOENT;
 124        }
 125
 126        davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
 127        if (!davinci_sram_suspend) {
 128                dev_err(&pdev->dev, "cannot allocate SRAM memory\n");
 129                return -ENOMEM;
 130        }
 131
 132        davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
 133                                                davinci_cpu_suspend_sz);
 134
 135        suspend_set_ops(&davinci_pm_ops);
 136
 137        return 0;
 138}
 139
 140static int __exit davinci_pm_remove(struct platform_device *pdev)
 141{
 142        sram_free(davinci_sram_suspend, davinci_cpu_suspend_sz);
 143        return 0;
 144}
 145
 146static struct platform_driver davinci_pm_driver = {
 147        .driver = {
 148                .name    = "pm-davinci",
 149                .owner   = THIS_MODULE,
 150        },
 151        .remove = __exit_p(davinci_pm_remove),
 152};
 153
 154static int __init davinci_pm_init(void)
 155{
 156        return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
 157}
 158late_initcall(davinci_pm_init);
 159