/* * 68328 Power Management Routines * * Copyright (C) 2002 Daniel Potts * * 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 */ /* * Debug macros */ #define DEBUG 1 #ifdef DEBUG # define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) #else # define DPRINTK(fmt, args...) #endif #include #include #include #include #include #include /* WARNING: included for CTL_ACPI and ACPI_S1_SLP_TYP */ #include #include /* for interrupt stuff (that shouldn't be here)*/ #include unsigned long sleep_irq_mask = 0L; /* irqs to enable while in sleep mode */ #ifdef CONFIG_68328_SERIAL void shutdown_console(void); void startup_console(void); #endif void set_sleep_mask(unsigned long mask) { sleep_irq_mask = mask; } int cpu_suspend(void) { unsigned long flags; unsigned long imr_flags; /* ZZZZzzzz */ save_flags(flags); cli(); imr_flags = IMR; #ifdef CONFIG_68328_SERIAL /* Console is shutdown here as a special device, * to ensure that the kernel will not hang trying to write to console. */ shutdown_console(); #endif /* write out sleep enabled interrupts */ IMR = ~(sleep_irq_mask); #if 1 /* Stop clock - DOZE mode */ PCTRL = PCTRL_PCEN; #else PLLCR |= PLLCR_DISPLL; #endif __asm__("stop #0x2000" : : : "cc"); #ifdef CONFIG_68328_SERIAL startup_console(); #endif IMR = imr_flags; restore_flags(flags); return 0; } static int sysctl_pm_do_suspend(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { int r = 0; *lenp = 0; DPRINTK("Suspending..\n"); r = pm_send_all(PM_SUSPEND, (void *)2); if (r) { return r; } r = cpu_suspend(); pm_send_all(PM_RESUME, (void *)0); DPRINTK("Resumed..\n"); return r; } static struct ctl_table pm_table[] = { {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend}, {0} }; static struct ctl_table pm_dir_table[] = { {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, {0} }; void pm_irq(int irq, void *dev_id, struct pt_regs *regs) { { unsigned long flags; save_flags(flags); cli(); ISR |= ISR_IRQ3; /* ack edge interrupt */ PDSEL |= 0x01; PDDIR |= 0x01; PDDATA ^= 0x01; restore_flags(flags); } } /* * Initialize power interface */ static int __init pm_init(void) { printk("Power management driver for 68328, Daniel Potts\n"); /* register a "power button" that we wait on when sleeping */ power_button(); register_sysctl_table(pm_dir_table, 1); return 0; } __initcall(pm_init); /* power_button(): BELONGS IN ANOTHER FILE: */ void power_button() { int err; unsigned long flags; /* init interrupt section */ PDDIR &= ~PD_IRQ3; PDSEL &= ~PD_IRQ3; ICR |= ( ICR_ET3); /* edge sensitive */ ISR |= ISR_IRQ3; /* clear it */ set_sleep_mask(IMR_MIRQ3); err = request_irq(IRQ3_IRQ_NUM, pm_irq, IRQ_FLG_STD, "power button", NULL); if(err) printk("power irq failed\n"); }