/* * arch/arm/mach-spc300/spc300-pm.c * * (C) Copyright 2009 SPiDCOM Technologies * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #ifdef CONFIG_CHIP_FEATURE_SRAM #include #include #endif #include #include #include "spc300.h" #ifdef CONFIG_CHIP_FEATURE_SRAM /* SRAM shared data. */ sram_data_t sram_data; static void (* pm_process) (void); static void map_extra_registers (void); static void unmap_extra_registers (void); /* Map hardware registers that are not used by the kernel, but that must be * accessed during the SRAM procedure. */ static void map_extra_registers (void) { sram_data.spll_addr = (unsigned int)ioremap(EXT_REG_BANK_BASE + MSEPLL_SPLL_OFFSET + MSEPLL_SPPLL_CTRL_OFFSET, SPLL_BANK_SIZE); sram_data.dsppll_addr = (unsigned int)ioremap(EXT_REG_BANK_BASE + MSEAFE_OFFSET + MSEAFE_DPLL_CTRL_OFFSET, DSPPLL_BANK_SIZE); } /* Unmap the previously mapped registers. */ static void unmap_extra_registers (void) { iounmap((void *)sram_data.spll_addr); iounmap((void *)sram_data.dsppll_addr); sram_data.spll_addr = 0; sram_data.dsppll_addr = 0; } #endif static bool spc300_pm_suspend_cmd; void spc300_pm_request_suspend (void) { spc300_pm_suspend_cmd = true; } void spc300_pm_clear_suspend (void) { spc300_pm_suspend_cmd = false; } static int spc300_pm_enter(suspend_state_t state) { BUG_ON(state != PM_SUSPEND_MEM); #ifdef CONFIG_CHIP_FEATURE_SRAM /* Map the required registers. */ map_extra_registers(); /* Copy data structure in SRAM. */ memcpy ((void *)SRAM_DATA_BASE_VA_PTR, &sram_data, sizeof(sram_data)); #endif spc300_irq_suspend(); local_irq_disable(); spc300_wdt_set_irq_mode(); #ifdef CONFIG_CHIP_FEATURE_SRAM pm_process(); /* Copy data structure from SRAM. */ memcpy (&sram_data, (void *)SRAM_DATA_BASE_VA_PTR, sizeof(sram_data)); /* Unmap the registers. */ unmap_extra_registers(); #endif /* Clear suspend request command */ spc300_pm_suspend_cmd = false; spc300_wdt_unset_irq_mode(); local_irq_enable(); spc300_irq_resume(); return 0; } static struct platform_suspend_ops spc300_pm_ops ={ .valid = suspend_valid_only_mem, .enter = spc300_pm_enter, }; /** * Read the PM data structure by /proc. * * \param file file structure. * \param buffer string pointer given by user. * \param start string pointer begin. * \param offset offset value. * \param count count parameter. * \param eof end of file. * \param data PM data structure. * \return new pointer position. */ static int spc300_readproc_pm(char *buf, char **start, off_t offset, int count, int *eof, void *data) { bool suspend_cmd = *(bool *)data; char *p; p = buf; p += sprintf(p, "%d\n", suspend_cmd); *eof = 1; return p-buf+1; } static int __init spc300_pm_init(void) { struct proc_dir_entry *pm_proc_dir; struct proc_dir_entry *entry; printk("SPC300: Power Management\n"); /* Initialize PM standby command. */ spc300_pm_suspend_cmd = false; #ifdef CONFIG_CHIP_FEATURE_SRAM /* Link SRAM part of the suspend process. */ pm_process = (void *) SRAM_BASE_VA_PTR; #endif suspend_set_ops(&spc300_pm_ops); /* Allow WDT IRQ to wake us up in low power mode. */ enable_irq_wake(INT_WDT); /* Create proc entry */ pm_proc_dir = proc_mkdir("pm", &proc_root); /* This entry is read only, so there is no write function and permissions * are set to 0444. */ entry = create_proc_entry("suspend_cmd", 0, pm_proc_dir); entry->read_proc = spc300_readproc_pm; entry->mode = S_IRUGO; entry->data = (void *)(&spc300_pm_suspend_cmd); return 0; } arch_initcall(spc300_pm_init);