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