Commit 3aa770e7972723f479122cf66b529017d2175289

Authored by Andriy Skulysh
Committed by Paul Mundt
1 parent ef48e8e349

sh: APM/PM support.

This adds some simple PM stubs and the basic APM interfaces,
primarily for use by hp6xx, where the existing userland
expects it.

Signed-off-by: Andriy Skulysh <askulysh@gmail.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

Showing 21 changed files with 1124 additions and 22 deletions Side-by-side Diff

... ... @@ -638,6 +638,16 @@
638 638  
639 639 endmenu
640 640  
  641 +menu "Power management options (EXPERIMENTAL)"
  642 +depends on EXPERIMENTAL
  643 +
  644 +source kernel/power/Kconfig
  645 +
  646 +config APM
  647 + bool "Advanced Power Management Emulation"
  648 + depends on PM
  649 +endmenu
  650 +
641 651 source "net/Kconfig"
642 652  
643 653 source "drivers/Kconfig"
arch/sh/boards/hp6xx/Makefile
... ... @@ -2,5 +2,7 @@
2 2 # Makefile for the HP6xx specific parts of the kernel
3 3 #
4 4  
5   -obj-y := mach.o setup.o
  5 +obj-y := mach.o setup.o
  6 +obj-$(CONFIG_PM) += pm.o pm_wakeup.o
  7 +obj-$(CONFIG_APM) += hp6xx_apm.o
arch/sh/boards/hp6xx/hp6xx_apm.c
  1 +/*
  2 + * bios-less APM driver for hp680
  3 + *
  4 + * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License.
  8 + */
  9 +#include <linux/config.h>
  10 +#include <linux/module.h>
  11 +#include <linux/apm_bios.h>
  12 +#include <linux/kernel.h>
  13 +#include <linux/init.h>
  14 +#include <linux/interrupt.h>
  15 +#include <asm/io.h>
  16 +#include <asm/apm.h>
  17 +#include <asm/adc.h>
  18 +#include <asm/hp6xx/hp6xx.h>
  19 +
  20 +#define SH7709_PGDR 0xa400012c
  21 +
  22 +#define APM_CRITICAL 10
  23 +#define APM_LOW 30
  24 +
  25 +#define HP680_BATTERY_MAX 875
  26 +#define HP680_BATTERY_MIN 600
  27 +#define HP680_BATTERY_AC_ON 900
  28 +
  29 +#define MODNAME "hp6x0_apm"
  30 +
  31 +static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
  32 +{
  33 + u8 pgdr;
  34 + char *p;
  35 + int battery_status;
  36 + int battery_flag;
  37 + int ac_line_status;
  38 + int time_units = APM_BATTERY_LIFE_UNKNOWN;
  39 +
  40 + int battery = adc_single(ADC_CHANNEL_BATTERY);
  41 + int backup = adc_single(ADC_CHANNEL_BACKUP);
  42 + int charging = adc_single(ADC_CHANNEL_CHARGE);
  43 + int percentage;
  44 +
  45 + percentage = 100 * (battery - HP680_BATTERY_MIN) /
  46 + (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
  47 +
  48 + ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
  49 + APM_AC_ONLINE : APM_AC_OFFLINE;
  50 +
  51 + p = buf;
  52 +
  53 + pgdr = ctrl_inb(SH7709_PGDR);
  54 + if (pgdr & PGDR_MAIN_BATTERY_OUT) {
  55 + battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
  56 + battery_flag = 0x80;
  57 + percentage = -1;
  58 + } else if (charging < 8 ) {
  59 + battery_status = APM_BATTERY_STATUS_CHARGING;
  60 + battery_flag = 0x08;
  61 + ac_line_status = 0xff;
  62 + } else if (percentage <= APM_CRITICAL) {
  63 + battery_status = APM_BATTERY_STATUS_CRITICAL;
  64 + battery_flag = 0x04;
  65 + } else if (percentage <= APM_LOW) {
  66 + battery_status = APM_BATTERY_STATUS_LOW;
  67 + battery_flag = 0x02;
  68 + } else {
  69 + battery_status = APM_BATTERY_STATUS_HIGH;
  70 + battery_flag = 0x01;
  71 + }
  72 +
  73 + p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
  74 + APM_32_BIT_SUPPORT,
  75 + ac_line_status,
  76 + battery_status,
  77 + battery_flag,
  78 + percentage,
  79 + time_units,
  80 + "min");
  81 + p += sprintf(p, "bat=%d backup=%d charge=%d\n",
  82 + battery, backup, charging);
  83 +
  84 + return p - buf;
  85 +}
  86 +
  87 +static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev, struct pt_regs *regs)
  88 +{
  89 + if (!apm_suspended)
  90 + apm_queue_event(APM_USER_SUSPEND);
  91 +
  92 + return IRQ_HANDLED;
  93 +}
  94 +
  95 +static int __init hp6x0_apm_init(void)
  96 +{
  97 + int ret;
  98 +
  99 + ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
  100 + SA_INTERRUPT, MODNAME, 0);
  101 + if (unlikely(ret < 0)) {
  102 + printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
  103 + HP680_BTN_IRQ);
  104 + return ret;
  105 + }
  106 +
  107 + apm_get_info = hp6x0_apm_get_info;
  108 +
  109 + return ret;
  110 +}
  111 +
  112 +static void __exit hp6x0_apm_exit(void)
  113 +{
  114 + free_irq(HP680_BTN_IRQ, 0);
  115 + apm_get_info = 0;
  116 +}
  117 +
  118 +module_init(hp6x0_apm_init);
  119 +module_exit(hp6x0_apm_exit);
  120 +
  121 +MODULE_AUTHOR("Adriy Skulysh");
  122 +MODULE_DESCRIPTION("hp6xx Advanced Power Management");
  123 +MODULE_LICENSE("GPL");
arch/sh/boards/hp6xx/pm.c
  1 +/*
  2 + * hp6x0 Power Management Routines
  3 + *
  4 + * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License.
  8 + */
  9 +#include <linux/config.h>
  10 +#include <linux/init.h>
  11 +#include <linux/suspend.h>
  12 +#include <linux/errno.h>
  13 +#include <linux/time.h>
  14 +#include <asm/io.h>
  15 +#include <asm/hd64461.h>
  16 +#include <asm/hp6xx/hp6xx.h>
  17 +#include <asm/cpu/dac.h>
  18 +#include <asm/pm.h>
  19 +
  20 +#define STBCR 0xffffff82
  21 +#define STBCR2 0xffffff88
  22 +
  23 +static int hp6x0_pm_enter(suspend_state_t state)
  24 +{
  25 + u8 stbcr, stbcr2;
  26 +#ifdef CONFIG_HD64461_ENABLER
  27 + u8 scr;
  28 + u16 hd64461_stbcr;
  29 +#endif
  30 +
  31 + if (state != PM_SUSPEND_MEM)
  32 + return -EINVAL;
  33 +
  34 +#ifdef CONFIG_HD64461_ENABLER
  35 + outb(0, HD64461_PCC1CSCIER);
  36 +
  37 + scr = inb(HD64461_PCC1SCR);
  38 + scr |= HD64461_PCCSCR_VCC1;
  39 + outb(scr, HD64461_PCC1SCR);
  40 +
  41 + hd64461_stbcr = inw(HD64461_STBCR);
  42 + hd64461_stbcr |= HD64461_STBCR_SPC1ST;
  43 + outw(hd64461_stbcr, HD64461_STBCR);
  44 +#endif
  45 +
  46 + ctrl_outb(0x1f, DACR);
  47 +
  48 + stbcr = ctrl_inb(STBCR);
  49 + ctrl_outb(0x01, STBCR);
  50 +
  51 + stbcr2 = ctrl_inb(STBCR2);
  52 + ctrl_outb(0x7f , STBCR2);
  53 +
  54 + outw(0xf07f, HD64461_SCPUCR);
  55 +
  56 + pm_enter();
  57 +
  58 + outw(0, HD64461_SCPUCR);
  59 + ctrl_outb(stbcr, STBCR);
  60 + ctrl_outb(stbcr2, STBCR2);
  61 +
  62 +#ifdef CONFIG_HD64461_ENABLER
  63 + hd64461_stbcr = inw(HD64461_STBCR);
  64 + hd64461_stbcr &= ~HD64461_STBCR_SPC1ST;
  65 + outw(hd64461_stbcr, HD64461_STBCR);
  66 +
  67 + outb(0x4c, HD64461_PCC1CSCIER);
  68 + outb(0x00, HD64461_PCC1CSCR);
  69 +#endif
  70 +
  71 + return 0;
  72 +}
  73 +
  74 +/*
  75 + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
  76 + */
  77 +static struct pm_ops hp6x0_pm_ops = {
  78 + .pm_disk_mode = PM_DISK_FIRMWARE,
  79 + .enter = hp6x0_pm_enter,
  80 +};
  81 +
  82 +static int __init hp6x0_pm_init(void)
  83 +{
  84 + pm_set_ops(&hp6x0_pm_ops);
  85 + return 0;
  86 +}
  87 +
  88 +late_initcall(hp6x0_pm_init);
arch/sh/boards/hp6xx/pm_wakeup.S
  1 +/*
  2 + * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
  3 + *
  4 + * This file is subject to the terms and conditions of the GNU General Public
  5 + * License. See the file "COPYING" in the main directory of this archive
  6 + * for more details.
  7 + *
  8 + */
  9 +
  10 +#include <linux/linkage.h>
  11 +#include <asm/cpu/mmu_context.h>
  12 +
  13 +#define k0 r0
  14 +#define k1 r1
  15 +#define k2 r2
  16 +#define k3 r3
  17 +#define k4 r4
  18 +
  19 +/*
  20 + * Kernel mode register usage:
  21 + * k0 scratch
  22 + * k1 scratch
  23 + * k2 scratch (Exception code)
  24 + * k3 scratch (Return address)
  25 + * k4 scratch
  26 + * k5 reserved
  27 + * k6 Global Interrupt Mask (0--15 << 4)
  28 + * k7 CURRENT_THREAD_INFO (pointer to current thread info)
  29 + */
  30 +
  31 +ENTRY(wakeup_start)
  32 +! clear STBY bit
  33 + mov #-126, k2
  34 + and #127, k0
  35 + mov.b k0, @k2
  36 +! enable refresh
  37 + mov.l 5f, k1
  38 + mov.w 6f, k0
  39 + mov.w k0, @k1
  40 +! jump to handler
  41 + mov.l 2f, k2
  42 + mov.l 3f, k3
  43 + mov.l @k2, k2
  44 +
  45 + mov.l 4f, k1
  46 + jmp @k1
  47 + nop
  48 +
  49 + .align 2
  50 +1: .long EXPEVT
  51 +2: .long INTEVT
  52 +3: .long ret_from_irq
  53 +4: .long handle_exception
  54 +5: .long 0xffffff68
  55 +6: .word 0x0524
  56 +
  57 +ENTRY(wakeup_end)
  58 + nop
arch/sh/boards/hp6xx/setup.c
... ... @@ -15,6 +15,9 @@
15 15 #include <asm/hp6xx/hp6xx.h>
16 16 #include <asm/cpu/dac.h>
17 17  
  18 +#define SCPCR 0xa4000116
  19 +#define SCPDR 0xa4000136
  20 +
18 21 const char *get_system_type(void)
19 22 {
20 23 return "HP6xx";
... ... @@ -24,6 +27,7 @@
24 27 {
25 28 u8 v8;
26 29 u16 v;
  30 +
27 31 v = inw(HD64461_STBCR);
28 32 v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
29 33 HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
... ... @@ -49,6 +53,16 @@
49 53 v8 = ctrl_inb(DACR);
50 54 v8 &= ~DACR_DAE;
51 55 ctrl_outb(v8,DACR);
  56 +
  57 + v8 = ctrl_inb(SCPDR);
  58 + v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
  59 + v8 &= ~SCPDR_TS_SCAN_ENABLE;
  60 + ctrl_outb(v8, SCPDR);
  61 +
  62 + v = ctrl_inw(SCPCR);
  63 + v &= ~SCPCR_TS_MASK;
  64 + v |= SCPCR_TS_ENABLE;
  65 + ctrl_outw(v, SCPCR);
52 66  
53 67 return 0;
54 68 }
arch/sh/kernel/Makefile
... ... @@ -18,4 +18,6 @@
18 18 obj-$(CONFIG_MODULES) += module.o
19 19 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
20 20 obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
  21 +obj-$(CONFIG_APM) += apm.o
  22 +obj-$(CONFIG_PM) += pm.o
arch/sh/kernel/apm.c
  1 +/*
  2 + * bios-less APM driver for hp680
  3 + *
  4 + * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
  5 + *
  6 + * based on ARM APM driver by
  7 + * Jamey Hicks <jamey@crl.dec.com>
  8 + *
  9 + * adapted from the APM BIOS driver for Linux by
  10 + * Stephen Rothwell (sfr@linuxcare.com)
  11 + *
  12 + * APM 1.2 Reference:
  13 + * Intel Corporation, Microsoft Corporation. Advanced Power Management
  14 + * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
  15 + *
  16 + * [This document is available from Microsoft at:
  17 + * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
  18 + */
  19 +#include <linux/config.h>
  20 +#include <linux/module.h>
  21 +#include <linux/poll.h>
  22 +#include <linux/timer.h>
  23 +#include <linux/slab.h>
  24 +#include <linux/proc_fs.h>
  25 +#include <linux/miscdevice.h>
  26 +#include <linux/apm_bios.h>
  27 +#include <linux/pm.h>
  28 +#include <linux/pm_legacy.h>
  29 +#include <asm/apm.h>
  30 +
  31 +#define MODNAME "apm"
  32 +
  33 +/*
  34 + * The apm_bios device is one of the misc char devices.
  35 + * This is its minor number.
  36 + */
  37 +#define APM_MINOR_DEV 134
  38 +
  39 +/*
  40 + * Maximum number of events stored
  41 + */
  42 +#define APM_MAX_EVENTS 16
  43 +
  44 +struct apm_queue {
  45 + unsigned int event_head;
  46 + unsigned int event_tail;
  47 + apm_event_t events[APM_MAX_EVENTS];
  48 +};
  49 +
  50 +/*
  51 + * The per-file APM data
  52 + */
  53 +struct apm_user {
  54 + struct list_head list;
  55 +
  56 + unsigned int suser: 1;
  57 + unsigned int writer: 1;
  58 + unsigned int reader: 1;
  59 +
  60 + int suspend_result;
  61 + unsigned int suspend_state;
  62 +#define SUSPEND_NONE 0 /* no suspend pending */
  63 +#define SUSPEND_PENDING 1 /* suspend pending read */
  64 +#define SUSPEND_READ 2 /* suspend read, pending ack */
  65 +#define SUSPEND_ACKED 3 /* suspend acked */
  66 +#define SUSPEND_DONE 4 /* suspend completed */
  67 +
  68 + struct apm_queue queue;
  69 +};
  70 +
  71 +/*
  72 + * Local variables
  73 + */
  74 +static int suspends_pending;
  75 +
  76 +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
  77 +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
  78 +
  79 +/*
  80 + * This is a list of everyone who has opened /dev/apm_bios
  81 + */
  82 +static DECLARE_RWSEM(user_list_lock);
  83 +static LIST_HEAD(apm_user_list);
  84 +
  85 +/*
  86 + * kapmd info. kapmd provides us a process context to handle
  87 + * "APM" events within - specifically necessary if we're going
  88 + * to be suspending the system.
  89 + */
  90 +static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
  91 +static DECLARE_COMPLETION(kapmd_exit);
  92 +static DEFINE_SPINLOCK(kapmd_queue_lock);
  93 +static struct apm_queue kapmd_queue;
  94 +
  95 +int apm_suspended;
  96 +EXPORT_SYMBOL(apm_suspended);
  97 +
  98 +/* Platform-specific apm_read_proc(). */
  99 +int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
  100 +EXPORT_SYMBOL(apm_get_info);
  101 +
  102 +/*
  103 + * APM event queue management.
  104 + */
  105 +static inline int queue_empty(struct apm_queue *q)
  106 +{
  107 + return q->event_head == q->event_tail;
  108 +}
  109 +
  110 +static inline apm_event_t queue_get_event(struct apm_queue *q)
  111 +{
  112 + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
  113 + return q->events[q->event_tail];
  114 +}
  115 +
  116 +static void queue_add_event(struct apm_queue *q, apm_event_t event)
  117 +{
  118 + q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
  119 + if (q->event_head == q->event_tail) {
  120 + static int notified;
  121 +
  122 + if (notified++ == 0)
  123 + printk(KERN_ERR "apm: an event queue overflowed\n");
  124 +
  125 + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
  126 + }
  127 + q->events[q->event_head] = event;
  128 +}
  129 +
  130 +static void queue_event_one_user(struct apm_user *as, apm_event_t event)
  131 +{
  132 + if (as->suser && as->writer) {
  133 + switch (event) {
  134 + case APM_SYS_SUSPEND:
  135 + case APM_USER_SUSPEND:
  136 + /*
  137 + * If this user already has a suspend pending,
  138 + * don't queue another one.
  139 + */
  140 + if (as->suspend_state != SUSPEND_NONE)
  141 + return;
  142 +
  143 + as->suspend_state = SUSPEND_PENDING;
  144 + suspends_pending++;
  145 + break;
  146 + }
  147 + }
  148 + queue_add_event(&as->queue, event);
  149 +}
  150 +
  151 +static void queue_event(apm_event_t event, struct apm_user *sender)
  152 +{
  153 + struct apm_user *as;
  154 +
  155 + down_read(&user_list_lock);
  156 +
  157 + list_for_each_entry(as, &apm_user_list, list)
  158 + if (as != sender && as->reader)
  159 + queue_event_one_user(as, event);
  160 +
  161 + up_read(&user_list_lock);
  162 + wake_up_interruptible(&apm_waitqueue);
  163 +}
  164 +
  165 +/**
  166 + * apm_queue_event - queue an APM event for kapmd
  167 + * @event: APM event
  168 + *
  169 + * Queue an APM event for kapmd to process and ultimately take the
  170 + * appropriate action. Only a subset of events are handled:
  171 + * %APM_LOW_BATTERY
  172 + * %APM_POWER_STATUS_CHANGE
  173 + * %APM_USER_SUSPEND
  174 + * %APM_SYS_SUSPEND
  175 + * %APM_CRITICAL_SUSPEND
  176 + */
  177 +void apm_queue_event(apm_event_t event)
  178 +{
  179 + spin_lock_irq(&kapmd_queue_lock);
  180 + queue_add_event(&kapmd_queue, event);
  181 + spin_unlock_irq(&kapmd_queue_lock);
  182 +
  183 + wake_up_interruptible(&kapmd_wait);
  184 +}
  185 +EXPORT_SYMBOL(apm_queue_event);
  186 +
  187 +static void apm_suspend(void)
  188 +{
  189 + struct apm_user *as;
  190 + int err;
  191 +
  192 + apm_suspended = 1;
  193 + err = pm_suspend(PM_SUSPEND_MEM);
  194 +
  195 + /*
  196 + * Anyone on the APM queues will think we're still suspended.
  197 + * Send a message so everyone knows we're now awake again.
  198 + */
  199 + queue_event(APM_NORMAL_RESUME, NULL);
  200 +
  201 + /*
  202 + * Finally, wake up anyone who is sleeping on the suspend.
  203 + */
  204 + down_read(&user_list_lock);
  205 + list_for_each_entry(as, &apm_user_list, list) {
  206 + as->suspend_result = err;
  207 + as->suspend_state = SUSPEND_DONE;
  208 + }
  209 + up_read(&user_list_lock);
  210 +
  211 + wake_up(&apm_suspend_waitqueue);
  212 + apm_suspended = 0;
  213 +}
  214 +
  215 +static ssize_t apm_read(struct file *fp, char __user *buf,
  216 + size_t count, loff_t *ppos)
  217 +{
  218 + struct apm_user *as = fp->private_data;
  219 + apm_event_t event;
  220 + int i = count, ret = 0;
  221 +
  222 + if (count < sizeof(apm_event_t))
  223 + return -EINVAL;
  224 +
  225 + if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
  226 + return -EAGAIN;
  227 +
  228 + wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
  229 +
  230 + while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
  231 + event = queue_get_event(&as->queue);
  232 +
  233 + ret = -EFAULT;
  234 + if (copy_to_user(buf, &event, sizeof(event)))
  235 + break;
  236 +
  237 + if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
  238 + as->suspend_state = SUSPEND_READ;
  239 +
  240 + buf += sizeof(event);
  241 + i -= sizeof(event);
  242 + }
  243 +
  244 + if (i < count)
  245 + ret = count - i;
  246 +
  247 + return ret;
  248 +}
  249 +
  250 +static unsigned int apm_poll(struct file *fp, poll_table * wait)
  251 +{
  252 + struct apm_user *as = fp->private_data;
  253 +
  254 + poll_wait(fp, &apm_waitqueue, wait);
  255 + return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
  256 +}
  257 +
  258 +/*
  259 + * apm_ioctl - handle APM ioctl
  260 + *
  261 + * APM_IOC_SUSPEND
  262 + * This IOCTL is overloaded, and performs two functions. It is used to:
  263 + * - initiate a suspend
  264 + * - acknowledge a suspend read from /dev/apm_bios.
  265 + * Only when everyone who has opened /dev/apm_bios with write permission
  266 + * has acknowledge does the actual suspend happen.
  267 + */
  268 +static int
  269 +apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
  270 +{
  271 + struct apm_user *as = filp->private_data;
  272 + unsigned long flags;
  273 + int err = -EINVAL;
  274 +
  275 + if (!as->suser || !as->writer)
  276 + return -EPERM;
  277 +
  278 + switch (cmd) {
  279 + case APM_IOC_SUSPEND:
  280 + as->suspend_result = -EINTR;
  281 +
  282 + if (as->suspend_state == SUSPEND_READ) {
  283 + /*
  284 + * If we read a suspend command from /dev/apm_bios,
  285 + * then the corresponding APM_IOC_SUSPEND ioctl is
  286 + * interpreted as an acknowledge.
  287 + */
  288 + as->suspend_state = SUSPEND_ACKED;
  289 + suspends_pending--;
  290 + } else {
  291 + /*
  292 + * Otherwise it is a request to suspend the system.
  293 + * Queue an event for all readers, and expect an
  294 + * acknowledge from all writers who haven't already
  295 + * acknowledged.
  296 + */
  297 + queue_event(APM_USER_SUSPEND, as);
  298 + }
  299 +
  300 + /*
  301 + * If there are no further acknowledges required, suspend
  302 + * the system.
  303 + */
  304 + if (suspends_pending == 0)
  305 + apm_suspend();
  306 +
  307 + /*
  308 + * Wait for the suspend/resume to complete. If there are
  309 + * pending acknowledges, we wait here for them.
  310 + *
  311 + * Note that we need to ensure that the PM subsystem does
  312 + * not kick us out of the wait when it suspends the threads.
  313 + */
  314 + flags = current->flags;
  315 + current->flags |= PF_NOFREEZE;
  316 +
  317 + /*
  318 + * Note: do not allow a thread which is acking the suspend
  319 + * to escape until the resume is complete.
  320 + */
  321 + if (as->suspend_state == SUSPEND_ACKED)
  322 + wait_event(apm_suspend_waitqueue,
  323 + as->suspend_state == SUSPEND_DONE);
  324 + else
  325 + wait_event_interruptible(apm_suspend_waitqueue,
  326 + as->suspend_state == SUSPEND_DONE);
  327 +
  328 + current->flags = flags;
  329 + err = as->suspend_result;
  330 + as->suspend_state = SUSPEND_NONE;
  331 + break;
  332 + }
  333 +
  334 + return err;
  335 +}
  336 +
  337 +static int apm_release(struct inode * inode, struct file * filp)
  338 +{
  339 + struct apm_user *as = filp->private_data;
  340 + filp->private_data = NULL;
  341 +
  342 + down_write(&user_list_lock);
  343 + list_del(&as->list);
  344 + up_write(&user_list_lock);
  345 +
  346 + /*
  347 + * We are now unhooked from the chain. As far as new
  348 + * events are concerned, we no longer exist. However, we
  349 + * need to balance suspends_pending, which means the
  350 + * possibility of sleeping.
  351 + */
  352 + if (as->suspend_state != SUSPEND_NONE) {
  353 + suspends_pending -= 1;
  354 + if (suspends_pending == 0)
  355 + apm_suspend();
  356 + }
  357 +
  358 + kfree(as);
  359 + return 0;
  360 +}
  361 +
  362 +static int apm_open(struct inode * inode, struct file * filp)
  363 +{
  364 + struct apm_user *as;
  365 +
  366 + as = kzalloc(sizeof(*as), GFP_KERNEL);
  367 + if (as) {
  368 + /*
  369 + * XXX - this is a tiny bit broken, when we consider BSD
  370 + * process accounting. If the device is opened by root, we
  371 + * instantly flag that we used superuser privs. Who knows,
  372 + * we might close the device immediately without doing a
  373 + * privileged operation -- cevans
  374 + */
  375 + as->suser = capable(CAP_SYS_ADMIN);
  376 + as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
  377 + as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
  378 +
  379 + down_write(&user_list_lock);
  380 + list_add(&as->list, &apm_user_list);
  381 + up_write(&user_list_lock);
  382 +
  383 + filp->private_data = as;
  384 + }
  385 +
  386 + return as ? 0 : -ENOMEM;
  387 +}
  388 +
  389 +static struct file_operations apm_bios_fops = {
  390 + .owner = THIS_MODULE,
  391 + .read = apm_read,
  392 + .poll = apm_poll,
  393 + .ioctl = apm_ioctl,
  394 + .open = apm_open,
  395 + .release = apm_release,
  396 +};
  397 +
  398 +static struct miscdevice apm_device = {
  399 + .minor = APM_MINOR_DEV,
  400 + .name = "apm_bios",
  401 + .fops = &apm_bios_fops
  402 +};
  403 +
  404 +
  405 +#ifdef CONFIG_PROC_FS
  406 +/*
  407 + * Arguments, with symbols from linux/apm_bios.h.
  408 + *
  409 + * 0) Linux driver version (this will change if format changes)
  410 + * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
  411 + * 2) APM flags from APM Installation Check (0x00):
  412 + * bit 0: APM_16_BIT_SUPPORT
  413 + * bit 1: APM_32_BIT_SUPPORT
  414 + * bit 2: APM_IDLE_SLOWS_CLOCK
  415 + * bit 3: APM_BIOS_DISABLED
  416 + * bit 4: APM_BIOS_DISENGAGED
  417 + * 3) AC line status
  418 + * 0x00: Off-line
  419 + * 0x01: On-line
  420 + * 0x02: On backup power (BIOS >= 1.1 only)
  421 + * 0xff: Unknown
  422 + * 4) Battery status
  423 + * 0x00: High
  424 + * 0x01: Low
  425 + * 0x02: Critical
  426 + * 0x03: Charging
  427 + * 0x04: Selected battery not present (BIOS >= 1.2 only)
  428 + * 0xff: Unknown
  429 + * 5) Battery flag
  430 + * bit 0: High
  431 + * bit 1: Low
  432 + * bit 2: Critical
  433 + * bit 3: Charging
  434 + * bit 7: No system battery
  435 + * 0xff: Unknown
  436 + * 6) Remaining battery life (percentage of charge):
  437 + * 0-100: valid
  438 + * -1: Unknown
  439 + * 7) Remaining battery life (time units):
  440 + * Number of remaining minutes or seconds
  441 + * -1: Unknown
  442 + * 8) min = minutes; sec = seconds
  443 + */
  444 +static int apm_read_proc(char *buf, char **start, off_t fpos, int length)
  445 +{
  446 + if (likely(apm_get_info))
  447 + return apm_get_info(buf, start, fpos, length);
  448 +
  449 + return -EINVAL;
  450 +}
  451 +#endif
  452 +
  453 +static int kapmd(void *arg)
  454 +{
  455 + daemonize("kapmd");
  456 + current->flags |= PF_NOFREEZE;
  457 +
  458 + do {
  459 + apm_event_t event;
  460 +
  461 + wait_event_interruptible(kapmd_wait,
  462 + !queue_empty(&kapmd_queue) || !pm_active);
  463 +
  464 + if (!pm_active)
  465 + break;
  466 +
  467 + spin_lock_irq(&kapmd_queue_lock);
  468 + event = 0;
  469 + if (!queue_empty(&kapmd_queue))
  470 + event = queue_get_event(&kapmd_queue);
  471 + spin_unlock_irq(&kapmd_queue_lock);
  472 +
  473 + switch (event) {
  474 + case 0:
  475 + break;
  476 +
  477 + case APM_LOW_BATTERY:
  478 + case APM_POWER_STATUS_CHANGE:
  479 + queue_event(event, NULL);
  480 + break;
  481 +
  482 + case APM_USER_SUSPEND:
  483 + case APM_SYS_SUSPEND:
  484 + queue_event(event, NULL);
  485 + if (suspends_pending == 0)
  486 + apm_suspend();
  487 + break;
  488 +
  489 + case APM_CRITICAL_SUSPEND:
  490 + apm_suspend();
  491 + break;
  492 + }
  493 + } while (1);
  494 +
  495 + complete_and_exit(&kapmd_exit, 0);
  496 +}
  497 +
  498 +static int __init apm_init(void)
  499 +{
  500 + int ret;
  501 +
  502 + pm_active = 1;
  503 +
  504 + ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
  505 + if (unlikely(ret < 0)) {
  506 + pm_active = 0;
  507 + return ret;
  508 + }
  509 +
  510 + create_proc_info_entry("apm", 0, NULL, apm_read_proc);
  511 +
  512 + ret = misc_register(&apm_device);
  513 + if (unlikely(ret != 0)) {
  514 + remove_proc_entry("apm", NULL);
  515 +
  516 + pm_active = 0;
  517 + wake_up(&kapmd_wait);
  518 + wait_for_completion(&kapmd_exit);
  519 + }
  520 +
  521 + return ret;
  522 +}
  523 +
  524 +static void __exit apm_exit(void)
  525 +{
  526 + misc_deregister(&apm_device);
  527 + remove_proc_entry("apm", NULL);
  528 +
  529 + pm_active = 0;
  530 + wake_up(&kapmd_wait);
  531 + wait_for_completion(&kapmd_exit);
  532 +}
  533 +
  534 +module_init(apm_init);
  535 +module_exit(apm_exit);
  536 +
  537 +MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh");
  538 +MODULE_DESCRIPTION("Advanced Power Management");
  539 +MODULE_LICENSE("GPL");
arch/sh/kernel/entry.S
... ... @@ -308,7 +308,7 @@
308 308 .align 2
309 309 ret_from_exception:
310 310 preempt_stop()
311   -ret_from_irq:
  311 +ENTRY(ret_from_irq)
312 312 !
313 313 mov #OFF_SR, r0
314 314 mov.l @(r0,r15), r0 ! get status register
... ... @@ -704,7 +704,7 @@
704 704 !
705 705 !
706 706 .align 2
707   -handle_exception:
  707 +ENTRY(handle_exception)
708 708 ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
709 709 ! save all registers onto stack.
710 710 !
  1 +/*
  2 + * Generic Power Management Routine
  3 + *
  4 + * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License.
  8 + */
  9 +#include <linux/suspend.h>
  10 +#include <linux/delay.h>
  11 +#include <linux/gfp.h>
  12 +#include <asm/freq.h>
  13 +#include <asm/io.h>
  14 +#include <asm/watchdog.h>
  15 +#include <asm/pm.h>
  16 +
  17 +#define INTR_OFFSET 0x600
  18 +
  19 +#define STBCR 0xffffff82
  20 +#define STBCR2 0xffffff88
  21 +
  22 +#define STBCR_STBY 0x80
  23 +#define STBCR_MSTP2 0x04
  24 +
  25 +#define MCR 0xffffff68
  26 +#define RTCNT 0xffffff70
  27 +
  28 +#define MCR_RMODE 2
  29 +#define MCR_RFSH 4
  30 +
  31 +void pm_enter(void)
  32 +{
  33 + u8 stbcr, csr;
  34 + u16 frqcr, mcr;
  35 + u32 vbr_new, vbr_old;
  36 +
  37 + set_bl_bit();
  38 +
  39 + /* set wdt */
  40 + csr = sh_wdt_read_csr();
  41 + csr &= ~WTCSR_TME;
  42 + csr |= WTCSR_CKS_4096;
  43 + sh_wdt_write_csr(csr);
  44 + csr = sh_wdt_read_csr();
  45 + sh_wdt_write_cnt(0);
  46 +
  47 + /* disable PLL1 */
  48 + frqcr = ctrl_inw(FRQCR);
  49 + frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
  50 + ctrl_outw(frqcr, FRQCR);
  51 +
  52 + /* enable standby */
  53 + stbcr = ctrl_inb(STBCR);
  54 + ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
  55 +
  56 + /* set self-refresh */
  57 + mcr = ctrl_inw(MCR);
  58 + ctrl_outw(mcr & ~MCR_RFSH, MCR);
  59 +
  60 + /* set interrupt handler */
  61 + asm volatile("stc vbr, %0" : "=r" (vbr_old));
  62 + vbr_new = get_zeroed_page(GFP_ATOMIC);
  63 + udelay(50);
  64 + memcpy((void*)(vbr_new + INTR_OFFSET),
  65 + &wakeup_start, &wakeup_end - &wakeup_start);
  66 + asm volatile("ldc %0, vbr" : : "r" (vbr_new));
  67 +
  68 + ctrl_outw(0, RTCNT);
  69 + ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
  70 +
  71 + cpu_sleep();
  72 +
  73 + asm volatile("ldc %0, vbr" : : "r" (vbr_old));
  74 +
  75 + free_page(vbr_new);
  76 +
  77 + /* enable PLL1 */
  78 + frqcr = ctrl_inw(FRQCR);
  79 + frqcr |= FRQCR_PSTBY;
  80 + ctrl_outw(frqcr, FRQCR);
  81 + udelay(50);
  82 + frqcr |= FRQCR_PLLEN;
  83 + ctrl_outw(frqcr, FRQCR);
  84 +
  85 + ctrl_outb(stbcr, STBCR);
  86 +
  87 + clear_bl_bit();
  88 +}
arch/sh/kernel/sh_ksyms.c
... ... @@ -116,6 +116,10 @@
116 116 EXPORT_SYMBOL(synchronize_irq);
117 117 #endif
118 118  
  119 +#ifdef CONFIG_PM
  120 +EXPORT_SYMBOL(pm_suspend);
  121 +#endif
  122 +
119 123 EXPORT_SYMBOL(csum_partial);
120 124 #ifdef CONFIG_IPV6
121 125 EXPORT_SYMBOL(csum_ipv6_magic);
arch/sh/kernel/time.c
... ... @@ -143,8 +143,33 @@
143 143 }
144 144 }
145 145  
  146 +#ifdef CONFIG_PM
  147 +int timer_suspend(struct sys_device *dev, pm_message_t state)
  148 +{
  149 + struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
  150 +
  151 + sys_timer->ops->stop();
  152 +
  153 + return 0;
  154 +}
  155 +
  156 +int timer_resume(struct sys_device *dev)
  157 +{
  158 + struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
  159 +
  160 + sys_timer->ops->start();
  161 +
  162 + return 0;
  163 +}
  164 +#else
  165 +#define timer_suspend NULL
  166 +#define timer_resume NULL
  167 +#endif
  168 +
146 169 static struct sysdev_class timer_sysclass = {
147 170 set_kset_name("timer"),
  171 + .suspend = timer_suspend,
  172 + .resume = timer_resume,
148 173 };
149 174  
150 175 static int __init timer_init_sysfs(void)
arch/sh/kernel/timers/timer-tmu.c
... ... @@ -188,6 +188,18 @@
188 188 .ops = &tmu_clk_ops,
189 189 };
190 190  
  191 +static int tmu_timer_start(void)
  192 +{
  193 + ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
  194 + return 0;
  195 +}
  196 +
  197 +static int tmu_timer_stop(void)
  198 +{
  199 + ctrl_outb(0, TMU_TSTR);
  200 + return 0;
  201 +}
  202 +
191 203 static int tmu_timer_init(void)
192 204 {
193 205 unsigned long interval;
... ... @@ -197,7 +209,7 @@
197 209 tmu0_clk.parent = clk_get("module_clk");
198 210  
199 211 /* Start TMU0 */
200   - ctrl_outb(0, TMU_TSTR);
  212 + tmu_timer_stop();
201 213 #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
202 214 ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
203 215 #endif
204 216  
... ... @@ -211,13 +223,15 @@
211 223 ctrl_outl(interval, TMU0_TCOR);
212 224 ctrl_outl(interval, TMU0_TCNT);
213 225  
214   - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
  226 + tmu_timer_start();
215 227  
216 228 return 0;
217 229 }
218 230  
219 231 struct sys_timer_ops tmu_timer_ops = {
220 232 .init = tmu_timer_init,
  233 + .start = tmu_timer_start,
  234 + .stop = tmu_timer_stop,
221 235 .get_frequency = tmu_timer_get_frequency,
222 236 .get_offset = tmu_timer_get_offset,
223 237 };
drivers/input/touchscreen/hp680_ts_input.c
... ... @@ -15,7 +15,6 @@
15 15 #define HP680_TS_ABS_Y_MIN 80
16 16 #define HP680_TS_ABS_Y_MAX 910
17 17  
18   -#define SCPCR 0xa4000116
19 18 #define PHDR 0xa400012e
20 19 #define SCPDR 0xa4000136
21 20  
... ... @@ -77,19 +76,6 @@
77 76  
78 77 static int __init hp680_ts_init(void)
79 78 {
80   - u8 scpdr;
81   - u16 scpcr;
82   -
83   - scpdr = ctrl_inb(SCPDR);
84   - scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
85   - scpdr &= ~SCPDR_TS_SCAN_ENABLE;
86   - ctrl_outb(scpdr, SCPDR);
87   -
88   - scpcr = ctrl_inw(SCPCR);
89   - scpcr &= ~SCPCR_TS_MASK;
90   - scpcr |= SCPCR_TS_ENABLE;
91   - ctrl_outw(scpcr, SCPCR);
92   -
93 79 hp680_ts_dev = input_allocate_device();
94 80 if (!hp680_ts_dev)
95 81 return -ENOMEM;
include/asm-sh/apm.h
  1 +/*
  2 + * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com>
  3 + *
  4 + * This file is subject to the terms and conditions of the GNU General Public
  5 + * License. See the file "COPYING" in the main directory of this archive
  6 + * for more details.
  7 + *
  8 + */
  9 +
  10 +#ifndef __ASM_SH_APM_H
  11 +#define __ASM_SH_APM_H
  12 +
  13 +#define APM_AC_OFFLINE 0
  14 +#define APM_AC_ONLINE 1
  15 +#define APM_AC_BACKUP 2
  16 +#define APM_AC_UNKNOWN 0xff
  17 +
  18 +#define APM_BATTERY_STATUS_HIGH 0
  19 +#define APM_BATTERY_STATUS_LOW 1
  20 +#define APM_BATTERY_STATUS_CRITICAL 2
  21 +#define APM_BATTERY_STATUS_CHARGING 3
  22 +#define APM_BATTERY_STATUS_NOT_PRESENT 4
  23 +#define APM_BATTERY_STATUS_UNKNOWN 0xff
  24 +
  25 +#define APM_BATTERY_LIFE_UNKNOWN 0xFFFF
  26 +#define APM_BATTERY_LIFE_MINUTES 0x8000
  27 +#define APM_BATTERY_LIFE_VALUE_MASK 0x7FFF
  28 +
  29 +#define APM_BATTERY_FLAG_HIGH (1 << 0)
  30 +#define APM_BATTERY_FLAG_LOW (1 << 1)
  31 +#define APM_BATTERY_FLAG_CRITICAL (1 << 2)
  32 +#define APM_BATTERY_FLAG_CHARGING (1 << 3)
  33 +#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7)
  34 +#define APM_BATTERY_FLAG_UNKNOWN 0xff
  35 +
  36 +#define APM_UNITS_MINS 0
  37 +#define APM_UNITS_SECS 1
  38 +#define APM_UNITS_UNKNOWN -1
  39 +
  40 +
  41 +extern int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
  42 +extern int apm_suspended;
  43 +
  44 +void apm_queue_event(apm_event_t event);
  45 +
  46 +#endif
include/asm-sh/cpu-sh3/freq.h
... ... @@ -18,5 +18,9 @@
18 18 #define MIN_DIVISOR_NR 0
19 19 #define MAX_DIVISOR_NR 4
20 20  
  21 +#define FRQCR_CKOEN 0x0100
  22 +#define FRQCR_PLLEN 0x0080
  23 +#define FRQCR_PSTBY 0x0040
  24 +
21 25 #endif /* __ASM_CPU_SH3_FREQ_H */
include/asm-sh/hd64461.h
... ... @@ -40,7 +40,12 @@
40 40 #define HD64461_LCDCBAR 0x11000
41 41 #define HD64461_LCDCLOR 0x11002
42 42 #define HD64461_LCDCCR 0x11004
43   -#define HD64461_LCDCCR_MOFF 0x80
  43 +#define HD64461_LCDCCR_STBACK 0x0400
  44 +#define HD64461_LCDCCR_STREQ 0x0100
  45 +#define HD64461_LCDCCR_MOFF 0x0080
  46 +#define HD64461_LCDCCR_REFSEL 0x0040
  47 +#define HD64461_LCDCCR_EPON 0x0020
  48 +#define HD64461_LCDCCR_SPON 0x0010
44 49  
45 50 #define HD64461_LDR1 0x11010
46 51 #define HD64461_LDR1_DON 0x01
include/asm-sh/hp6xx/hp6xx.h
... ... @@ -2,16 +2,33 @@
2 2 #define __ASM_SH_HP6XX_H
3 3  
4 4 /*
5   - * Copyright (C) 2003 Andriy Skulysh
  5 + * Copyright (C) 2003, 2004, 2005 Andriy Skulysh
  6 + *
  7 + * This file is subject to the terms and conditions of the GNU General Public
  8 + * License. See the file "COPYING" in the main directory of this archive
  9 + * for more details.
  10 + *
6 11 */
7 12  
8   -#define HP680_TS_IRQ IRQ3_IRQ
  13 +#define HP680_BTN_IRQ IRQ0_IRQ
  14 +#define HP680_TS_IRQ IRQ3_IRQ
  15 +#define HP680_HD64461_IRQ IRQ4_IRQ
9 16  
10 17 #define DAC_LCD_BRIGHTNESS 0
11 18 #define DAC_SPEAKER_VOLUME 1
12 19  
  20 +#define PGDR_OPENED 0x01
  21 +#define PGDR_MAIN_BATTERY_OUT 0x04
  22 +#define PGDR_PLAY_BUTTON 0x08
  23 +#define PGDR_REWIND_BUTTON 0x10
  24 +#define PGDR_RECORD_BUTTON 0x20
  25 +
13 26 #define PHDR_TS_PEN_DOWN 0x08
14 27  
  28 +#define PJDR_LED_BLINK 0x02
  29 +
  30 +#define PKDR_LED_GREEN 0x10
  31 +
15 32 #define SCPDR_TS_SCAN_ENABLE 0x20
16 33 #define SCPDR_TS_SCAN_Y 0x02
17 34 #define SCPDR_TS_SCAN_X 0x01
18 35  
19 36  
20 37  
... ... @@ -21,11 +38,43 @@
21 38  
22 39 #define ADC_CHANNEL_TS_Y 1
23 40 #define ADC_CHANNEL_TS_X 2
  41 +#define ADC_CHANNEL_BATTERY 3
  42 +#define ADC_CHANNEL_BACKUP 4
  43 +#define ADC_CHANNEL_CHARGE 5
24 44  
25 45 #define HD64461_GPADR_SPEAKER 0x01
26 46 #define HD64461_GPADR_PCMCIA0 (0x02|0x08)
  47 +
27 48 #define HD64461_GPBDR_LCDOFF 0x01
  49 +#define HD64461_GPBDR_LCD_CONTRAST_MASK 0x78
28 50 #define HD64461_GPBDR_LED_RED 0x80
  51 +
  52 +#include <asm/hd64461.h>
  53 +#include <asm/io.h>
  54 +
  55 +#define PJDR 0xa4000130
  56 +#define PKDR 0xa4000132
  57 +
  58 +static inline void hp6xx_led_red(int on)
  59 +{
  60 + u16 v16;
  61 + v16 = ctrl_inw(CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
  62 + if (on)
  63 + ctrl_outw(v16 & (~HD64461_GPBDR_LED_RED), CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
  64 + else
  65 + ctrl_outw(v16 | HD64461_GPBDR_LED_RED, CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
  66 +}
  67 +
  68 +static inline void hp6xx_led_green(int on)
  69 +{
  70 + u8 v8;
  71 +
  72 + v8 = ctrl_inb(PKDR);
  73 + if (on)
  74 + ctrl_outb(v8 & (~PKDR_LED_GREEN), PKDR);
  75 + else
  76 + ctrl_outb(v8 | PKDR_LED_GREEN, PKDR);
  77 +}
29 78  
30 79  
31 80 #endif /* __ASM_SH_HP6XX_H */
  1 +/*
  2 + * This file is subject to the terms and conditions of the GNU General Public
  3 + * License. See the file "COPYING" in the main directory of this archive
  4 + * for more details.
  5 + *
  6 + * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com>
  7 + *
  8 + */
  9 +#ifndef __ASM_SH_PM_H
  10 +#define __ASM_SH_PM_H
  11 +
  12 +extern u8 wakeup_start;
  13 +extern u8 wakeup_end;
  14 +
  15 +void pm_enter(void);
  16 +
  17 +#endif
include/asm-sh/system.h
... ... @@ -172,6 +172,31 @@
172 172 : "memory");
173 173 }
174 174  
  175 +static __inline__ void set_bl_bit(void)
  176 +{
  177 + unsigned long __dummy0, __dummy1;
  178 +
  179 + __asm__ __volatile__ ("stc sr, %0\n\t"
  180 + "or %2, %0\n\t"
  181 + "and %3, %0\n\t"
  182 + "ldc %0, sr"
  183 + : "=&r" (__dummy0), "=r" (__dummy1)
  184 + : "r" (0x10000000), "r" (0xffffff0f)
  185 + : "memory");
  186 +}
  187 +
  188 +static __inline__ void clear_bl_bit(void)
  189 +{
  190 + unsigned long __dummy0, __dummy1;
  191 +
  192 + __asm__ __volatile__ ("stc sr, %0\n\t"
  193 + "and %2, %0\n\t"
  194 + "ldc %0, sr"
  195 + : "=&r" (__dummy0), "=r" (__dummy1)
  196 + : "1" (~0x10000000)
  197 + : "memory");
  198 +}
  199 +
175 200 #define local_save_flags(x) \
176 201 __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" )
177 202  
include/asm-sh/timer.h
... ... @@ -6,6 +6,8 @@
6 6  
7 7 struct sys_timer_ops {
8 8 int (*init)(void);
  9 + int (*start)(void);
  10 + int (*stop)(void);
9 11 unsigned long (*get_offset)(void);
10 12 unsigned long (*get_frequency)(void);
11 13 };