mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-28 22:18:58 +02:00
jz4740: Cleanup powermanagemnt code. Add inital suspend support.
This commit is contained in:
parent
12f85f8a91
commit
27ca1adf36
@ -66,6 +66,9 @@
|
|||||||
#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
|
#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
|
||||||
|
|
||||||
#define GPIO_TO_REG(gpio, reg) (jz_gpio_base + ((gpio >> 5) << 8) + reg)
|
#define GPIO_TO_REG(gpio, reg) (jz_gpio_base + ((gpio >> 5) << 8) + reg)
|
||||||
|
#define GPIO_TO_MASK_REG(gpio) GPIO_TO_REG(gpio, 0x20)
|
||||||
|
#define GPIO_TO_MASK_SET_REG(gpio) GPIO_TO_REG(gpio, 0x24)
|
||||||
|
#define GPIO_TO_MASK_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x28)
|
||||||
#define GPIO_TO_PULL_REG(gpio) GPIO_TO_REG(gpio, 0x30)
|
#define GPIO_TO_PULL_REG(gpio) GPIO_TO_REG(gpio, 0x30)
|
||||||
#define GPIO_TO_PULL_SET_REG(gpio) GPIO_TO_REG(gpio, 0x34)
|
#define GPIO_TO_PULL_SET_REG(gpio) GPIO_TO_REG(gpio, 0x34)
|
||||||
#define GPIO_TO_PULL_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x38)
|
#define GPIO_TO_PULL_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x38)
|
||||||
@ -81,16 +84,23 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void __iomem *jz_gpio_base;
|
static void __iomem *jz_gpio_base;
|
||||||
static spinlock_t jz_gpio_lock;
|
static spinlock_t jz_gpio_lock;
|
||||||
|
|
||||||
struct jz_gpio_chip {
|
struct jz_gpio_chip {
|
||||||
|
unsigned int irq;
|
||||||
unsigned int irq_base;
|
unsigned int irq_base;
|
||||||
|
uint32_t wakeup;
|
||||||
|
uint32_t saved[4];
|
||||||
struct gpio_chip gpio_chip;
|
struct gpio_chip gpio_chip;
|
||||||
struct irq_chip irq_chip;
|
struct irq_chip irq_chip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct jz_gpio_chip *jz_irq_to_chip(unsigned int irq)
|
||||||
|
{
|
||||||
|
return get_irq_chip_data(irq);
|
||||||
|
}
|
||||||
|
|
||||||
int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
|
int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
|
||||||
{
|
{
|
||||||
if (function == JZ_GPIO_FUNC_NONE) {
|
if (function == JZ_GPIO_FUNC_NONE) {
|
||||||
@ -109,8 +119,8 @@ int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
|
|||||||
writew(GPIO_TO_BIT(gpio), GPIO_TO_SEL_SET_REG(gpio));
|
writew(GPIO_TO_BIT(gpio), GPIO_TO_SEL_SET_REG(gpio));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +311,18 @@ static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on)
|
||||||
|
{
|
||||||
|
struct jz_gpio_chip *chip = jz_irq_to_chip(irq);
|
||||||
|
if (on) {
|
||||||
|
chip->wakeup |= IRQ_TO_BIT(irq);
|
||||||
|
} else {
|
||||||
|
chip->wakeup &= ~IRQ_TO_BIT(irq);
|
||||||
|
}
|
||||||
|
set_irq_wake(chip->irq, on);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int gpio_to_irq(unsigned gpio)
|
int gpio_to_irq(unsigned gpio)
|
||||||
{
|
{
|
||||||
return JZ_IRQ_GPIO(0) + gpio;
|
return JZ_IRQ_GPIO(0) + gpio;
|
||||||
@ -309,7 +331,7 @@ EXPORT_SYMBOL_GPL(gpio_to_irq);
|
|||||||
|
|
||||||
int irq_to_gpio(unsigned gpio)
|
int irq_to_gpio(unsigned gpio)
|
||||||
{
|
{
|
||||||
return IRQ_TO_GPIO(gpio);
|
return IRQ_TO_GPIO(gpio);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(irq_to_gpio);
|
EXPORT_SYMBOL_GPL(irq_to_gpio);
|
||||||
|
|
||||||
@ -333,6 +355,7 @@ EXPORT_SYMBOL_GPL(irq_to_gpio);
|
|||||||
.startup = jz_gpio_irq_startup, \
|
.startup = jz_gpio_irq_startup, \
|
||||||
.shutdown = jz_gpio_irq_shutdown, \
|
.shutdown = jz_gpio_irq_shutdown, \
|
||||||
.set_type = jz_gpio_irq_set_type, \
|
.set_type = jz_gpio_irq_set_type, \
|
||||||
|
.set_wake = jz_gpio_irq_set_wake, \
|
||||||
}, \
|
}, \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,13 +375,37 @@ int __init jz_gpiolib_init(void)
|
|||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
|
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
|
||||||
gpiochip_add(&chip->gpio_chip);
|
gpiochip_add(&chip->gpio_chip);
|
||||||
set_irq_chained_handler(JZ_IRQ_INTC_GPIO(i), jz_gpio_irq_demux_handler);
|
chip->irq = JZ_IRQ_INTC_GPIO(i);
|
||||||
|
set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
|
||||||
for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio;
|
for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio;
|
||||||
++irq)
|
++irq) {
|
||||||
set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
|
set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
|
||||||
|
set_irq_chip_data(irq, chip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("JZ GPIO initalized\n");
|
printk("JZ GPIO initalized\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jz_gpiolib_suspend(void)
|
||||||
|
{
|
||||||
|
struct jz_gpio_chip *chip = jz_gpio_chips;
|
||||||
|
int i, gpio;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
|
||||||
|
gpio = chip->gpio_chip.base;
|
||||||
|
chip->saved[0] = readl(GPIO_TO_MASK_REG(gpio));
|
||||||
|
writel(~(chip->wakeup), GPIO_TO_MASK_SET_REG(gpio));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Use sysdev */
|
||||||
|
void jz_gpiolib_resume(void)
|
||||||
|
{
|
||||||
|
struct jz_gpio_chip *chip = jz_gpio_chips;
|
||||||
|
int i, gpio;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
|
||||||
|
writel(~(chip->saved[0]), GPIO_TO_MASK_CLEAR_REG(chip->gpio_chip.base));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
#include <asm/irq_cpu.h>
|
#include <asm/irq_cpu.h>
|
||||||
|
|
||||||
static void __iomem *jz_intc_base;
|
static void __iomem *jz_intc_base;
|
||||||
|
static uint32_t jz_intc_wakeup;
|
||||||
|
static uint32_t jz_intc_saved;
|
||||||
|
|
||||||
#define JZ_REG_BASE_INTC 0x10001000
|
#define JZ_REG_BASE_INTC 0x10001000
|
||||||
|
|
||||||
@ -69,12 +71,23 @@ static void intc_irq_end(unsigned int irq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int intc_irq_set_wake(unsigned int irq, unsigned int on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
jz_intc_wakeup |= IRQ_BIT(irq);
|
||||||
|
else
|
||||||
|
jz_intc_wakeup &= ~IRQ_BIT(irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct irq_chip intc_irq_type = {
|
static struct irq_chip intc_irq_type = {
|
||||||
.name = "INTC",
|
.name = "INTC",
|
||||||
.mask = intc_irq_mask,
|
.mask = intc_irq_mask,
|
||||||
.unmask = intc_irq_unmask,
|
.unmask = intc_irq_unmask,
|
||||||
.ack = intc_irq_ack,
|
.ack = intc_irq_ack,
|
||||||
.end = intc_irq_end,
|
.end = intc_irq_end,
|
||||||
|
.set_wake = intc_irq_set_wake,
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t jz4740_cascade(int irq, void *data)
|
static irqreturn_t jz4740_cascade(int irq, void *data)
|
||||||
@ -83,11 +96,11 @@ static irqreturn_t jz4740_cascade(int irq, void *data)
|
|||||||
irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
|
irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
|
||||||
|
|
||||||
if (irq_reg) {
|
if (irq_reg) {
|
||||||
generic_handle_irq(ffs(irq_reg) - 1 + JZ_IRQ_BASE);
|
generic_handle_irq(ffs(irq_reg) - 1 + JZ_IRQ_BASE);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irqaction jz4740_cascade_action = {
|
static struct irqaction jz4740_cascade_action = {
|
||||||
@ -98,7 +111,7 @@ static struct irqaction jz4740_cascade_action = {
|
|||||||
void __init arch_init_irq(void)
|
void __init arch_init_irq(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
mips_cpu_irq_init();
|
mips_cpu_irq_init();
|
||||||
|
|
||||||
jz_intc_base = ioremap(JZ_REG_BASE_INTC, 0x14);
|
jz_intc_base = ioremap(JZ_REG_BASE_INTC, 0x14);
|
||||||
|
|
||||||
@ -113,10 +126,23 @@ void __init arch_init_irq(void)
|
|||||||
asmlinkage void plat_irq_dispatch(void)
|
asmlinkage void plat_irq_dispatch(void)
|
||||||
{
|
{
|
||||||
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
||||||
if (pending & STATUSF_IP2)
|
if (pending & STATUSF_IP2)
|
||||||
jz4740_cascade(2, NULL);
|
jz4740_cascade(2, NULL);
|
||||||
else if(pending & STATUSF_IP3)
|
else if(pending & STATUSF_IP3)
|
||||||
do_IRQ(3);
|
do_IRQ(3);
|
||||||
else
|
else
|
||||||
spurious_interrupt();
|
spurious_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Use sysdev */
|
||||||
|
void jz4740_intc_suspend(void)
|
||||||
|
{
|
||||||
|
jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK);
|
||||||
|
printk("intc wakeup: %d\n", jz_intc_wakeup);
|
||||||
|
writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz4740_intc_resume(void)
|
||||||
|
{
|
||||||
|
writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
|
||||||
|
}
|
||||||
|
@ -23,273 +23,36 @@
|
|||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/proc_fs.h>
|
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <asm/cacheops.h>
|
|
||||||
#include <asm/jzsoc.h>
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
#undef DEBUG
|
extern void jz4740_intc_suspend(void);
|
||||||
//#define DEBUG
|
extern void jz4740_intc_resume(void);
|
||||||
#ifdef DEBUG
|
extern void jz_gpiolib_suspend(void);
|
||||||
#define dprintk(x...) printk(x)
|
extern void jz_gpiolib_resume(void);
|
||||||
#else
|
|
||||||
#define dprintk(x...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */
|
static int jz_pm_enter(suspend_state_t state)
|
||||||
|
|
||||||
/*
|
|
||||||
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
|
|
||||||
* except sdram, nand flash pins and the pins which can be used as CS1_N
|
|
||||||
* to CS4_N for chip select.
|
|
||||||
*/
|
|
||||||
#define __gpio_as_sleep() \
|
|
||||||
do { \
|
|
||||||
REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \
|
|
||||||
REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \
|
|
||||||
REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \
|
|
||||||
REG_GPIO_PXPES(1) = 0xffffffff; \
|
|
||||||
REG_GPIO_PXFUNC(2) = ~0x37000000; \
|
|
||||||
REG_GPIO_PXSELC(2) = ~0x37000000; \
|
|
||||||
REG_GPIO_PXDIRC(2) = ~0x37000000; \
|
|
||||||
REG_GPIO_PXPES(2) = 0xffffffff; \
|
|
||||||
REG_GPIO_PXFUNC(3) = 0xffffffff; \
|
|
||||||
REG_GPIO_PXSELC(3) = 0xffffffff; \
|
|
||||||
REG_GPIO_PXDIRC(3) = 0xffffffff; \
|
|
||||||
REG_GPIO_PXPES(3) = 0xffffffff; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static int jz_pm_do_hibernate(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Mask all interrupts */
|
|
||||||
REG_INTC_IMSR = 0xffffffff;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RTC Wakeup or 1Hz interrupt can be enabled or disabled
|
|
||||||
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
|
|
||||||
|
|
||||||
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
|
|
||||||
|
|
||||||
/* Scratch pad register to be reserved */
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
REG_RTC_HSPR = 0x12345678;
|
|
||||||
|
|
||||||
/* clear wakeup status register */
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
REG_RTC_HWRSR = 0x0;
|
|
||||||
|
|
||||||
/* Put CPU to power down mode */
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
REG_RTC_HCR = RTC_HCR_PD;
|
|
||||||
|
|
||||||
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
|
|
||||||
while(1);
|
|
||||||
|
|
||||||
/* We can't get here */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTES:
|
|
||||||
* 1: Pins that are floated (NC) should be set as input and pull-enable.
|
|
||||||
* 2: Pins that are pull-up or pull-down by outside should be set as input
|
|
||||||
* and pull-disable.
|
|
||||||
* 3: Pins that are connected to a chip except sdram and nand flash
|
|
||||||
* should be set as input and pull-disable, too.
|
|
||||||
*/
|
|
||||||
static void jz_board_do_sleep(unsigned long *ptr)
|
|
||||||
{
|
|
||||||
unsigned char i;
|
|
||||||
|
|
||||||
/* Print messages of GPIO registers for debug */
|
|
||||||
for(i=0;i<4;i++) {
|
|
||||||
dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
|
|
||||||
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
|
|
||||||
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save GPIO registers */
|
|
||||||
for(i = 1; i < 4; i++) {
|
|
||||||
*ptr++ = REG_GPIO_PXFUN(i);
|
|
||||||
*ptr++ = REG_GPIO_PXSEL(i);
|
|
||||||
*ptr++ = REG_GPIO_PXDIR(i);
|
|
||||||
*ptr++ = REG_GPIO_PXPE(i);
|
|
||||||
*ptr++ = REG_GPIO_PXIM(i);
|
|
||||||
*ptr++ = REG_GPIO_PXDAT(i);
|
|
||||||
*ptr++ = REG_GPIO_PXTRG(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set all pins to pull-disable, and set all pins as input except
|
|
||||||
* sdram, nand flash pins and the pins which can be used as CS1_N
|
|
||||||
* to CS4_N for chip select.
|
|
||||||
*/
|
|
||||||
__gpio_as_sleep();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set proper status for GPB25 to GPB28 which can be used as CS1_N to CS4_N.
|
|
||||||
* Keep the pins' function used for chip select(CS) here according to your
|
|
||||||
* system to avoid chip select crashing with sdram when resuming from sleep mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_JZ4740_PAVO)
|
|
||||||
/* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
|
|
||||||
|
|
||||||
/* GPB26/CS2_N is connected to nand flash, needn't be changed. */
|
|
||||||
|
|
||||||
/* GPB27/CS3_N is used as EXT_INT for CS8900 on debug board, it should be set as input.*/
|
|
||||||
__gpio_as_input(32+27);
|
|
||||||
|
|
||||||
/* GPB28/CS4_N is used as cs8900's chip select, shouldn't be changed. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable pull for NC pins here according to your system
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_JZ4740_PAVO)
|
|
||||||
/* GPB30-27 <-> J1: WE_N RD_N CS4_N EXT_INT */
|
|
||||||
for(i=27;i<31;i++) {
|
|
||||||
__gpio_enable_pull(32+i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPC27<-> WAIT_N */
|
|
||||||
__gpio_enable_pull(32*2+27);
|
|
||||||
|
|
||||||
/* GPD16<->SD_WP; GPD13-10<->MSC_D0-3; GPD9<->MSC_CMD; GPD8<->MSC_CLK */
|
|
||||||
__gpio_enable_pull(32*3+16);
|
|
||||||
for(i=8;i<14;i++) {
|
|
||||||
__gpio_enable_pull(32*3+i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If you must set some GPIOs as output to high level or low level,
|
|
||||||
* you can set them here, using:
|
|
||||||
* __gpio_as_output(n);
|
|
||||||
* __gpio_set_pin(n); or __gpio_clear_pin(n);
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_JZ4740_PAVO)
|
|
||||||
/* GPD16 which is used as AMPEN_N should be set to high to disable audio amplifier */
|
|
||||||
__gpio_set_pin(32*3+4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
/* Keep uart0 function for printing debug message */
|
|
||||||
__gpio_as_uart0();
|
|
||||||
|
|
||||||
/* Print messages of GPIO registers for debug */
|
|
||||||
for(i=0;i<4;i++) {
|
|
||||||
dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
|
|
||||||
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
|
|
||||||
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz_board_do_resume(unsigned long *ptr)
|
|
||||||
{
|
|
||||||
unsigned char i;
|
|
||||||
|
|
||||||
/* Restore GPIO registers */
|
|
||||||
for(i = 1; i < 4; i++) {
|
|
||||||
REG_GPIO_PXFUNS(i) = *ptr;
|
|
||||||
REG_GPIO_PXFUNC(i) = ~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXSELS(i) = *ptr;
|
|
||||||
REG_GPIO_PXSELC(i) = ~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXDIRS(i) = *ptr;
|
|
||||||
REG_GPIO_PXDIRC(i) = ~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXPES(i) = *ptr;
|
|
||||||
REG_GPIO_PXPEC(i) = ~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXIMS(i)=*ptr;
|
|
||||||
REG_GPIO_PXIMC(i)=~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXDATS(i)=*ptr;
|
|
||||||
REG_GPIO_PXDATC(i)=~(*ptr++);
|
|
||||||
|
|
||||||
REG_GPIO_PXTRGS(i)=*ptr;
|
|
||||||
REG_GPIO_PXTRGC(i)=~(*ptr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print messages of GPIO registers for debug */
|
|
||||||
for(i=0;i<4;i++) {
|
|
||||||
dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
|
|
||||||
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
|
|
||||||
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int jz_pm_do_sleep(void)
|
|
||||||
{
|
{
|
||||||
unsigned long delta;
|
unsigned long delta;
|
||||||
unsigned long nfcsr = REG_EMC_NFCSR;
|
unsigned long nfcsr = REG_EMC_NFCSR;
|
||||||
unsigned long scr = REG_CPM_SCR;
|
uint32_t scr = REG_CPM_SCR;
|
||||||
unsigned long imr = REG_INTC_IMR;
|
uint32_t sleep_gpio_save[7*3];
|
||||||
unsigned long sadc = REG_SADC_ENA;
|
|
||||||
unsigned long sleep_gpio_save[7*3];
|
|
||||||
|
|
||||||
/* Preserve current time */
|
/* Preserve current time */
|
||||||
delta = xtime.tv_sec - REG_RTC_RSR;
|
delta = xtime.tv_sec - REG_RTC_RSR;
|
||||||
|
|
||||||
/* Disable nand flash */
|
/* Disable nand flash */
|
||||||
REG_EMC_NFCSR = ~0xff;
|
REG_EMC_NFCSR = ~0xff;
|
||||||
|
|
||||||
/* stop sadc */
|
|
||||||
REG_SADC_ENA &= ~0x7;
|
|
||||||
while((REG_SADC_ENA & 0x7) != 0);
|
|
||||||
udelay(100);
|
udelay(100);
|
||||||
|
|
||||||
/*stop udc and usb*/
|
/*stop udc and usb*/
|
||||||
REG_CPM_SCR &= ~( 1<<6 | 1<<7);
|
REG_CPM_SCR &= ~( 1<<6 | 1<<7);
|
||||||
REG_CPM_SCR |= 0<<6 | 1<<7;
|
REG_CPM_SCR |= 0<<6 | 1<<7;
|
||||||
|
|
||||||
/* Sleep on-board modules */
|
jz_gpiolib_suspend();
|
||||||
jz_board_do_sleep(sleep_gpio_save);
|
jz4740_intc_suspend();
|
||||||
|
|
||||||
/* Mask all interrupts */
|
|
||||||
REG_INTC_IMSR = 0xffffffff;
|
|
||||||
|
|
||||||
/* Just allow following interrupts to wakeup the system.
|
|
||||||
* Note: modify this according to your system.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* enable RTC alarm */
|
|
||||||
__intc_unmask_irq(JZ_IRQ_RTC);
|
|
||||||
#if 0
|
|
||||||
/* make system wake up after n seconds by RTC alarm */
|
|
||||||
unsigned int v, n;
|
|
||||||
n = 10;
|
|
||||||
while (!__rtc_write_ready());
|
|
||||||
__rtc_enable_alarm();
|
|
||||||
while (!__rtc_write_ready());
|
|
||||||
__rtc_enable_alarm_irq();
|
|
||||||
while (!__rtc_write_ready());
|
|
||||||
v = __rtc_get_second();
|
|
||||||
while (!__rtc_write_ready());
|
|
||||||
__rtc_set_alarm_second(v+n);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* WAKEUP key */
|
|
||||||
__gpio_as_irq_rise_edge(GPIO_WAKEUP);
|
|
||||||
__gpio_unmask_irq(GPIO_WAKEUP);
|
|
||||||
__intc_unmask_irq(JZ_IRQ_GPIO3); /* IRQ_GPIOn depends on GPIO_WAKEUP */
|
|
||||||
|
|
||||||
/* Enter SLEEP mode */
|
/* Enter SLEEP mode */
|
||||||
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
|
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
|
||||||
@ -302,18 +65,11 @@ static int jz_pm_do_sleep(void)
|
|||||||
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
|
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
|
||||||
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
|
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
|
||||||
|
|
||||||
/* Restore nand flash control register */
|
/* Restore nand flash control register */
|
||||||
REG_EMC_NFCSR = nfcsr;
|
REG_EMC_NFCSR = nfcsr;
|
||||||
|
|
||||||
/* Restore interrupts */
|
jz4740_intc_resume();
|
||||||
REG_INTC_IMSR = imr;
|
jz_gpiolib_resume();
|
||||||
REG_INTC_IMCR = ~imr;
|
|
||||||
|
|
||||||
/* Restore sadc */
|
|
||||||
REG_SADC_ENA = sadc;
|
|
||||||
|
|
||||||
/* Resume on-board modules */
|
|
||||||
jz_board_do_resume(sleep_gpio_save);
|
|
||||||
|
|
||||||
/* Restore sleep control register */
|
/* Restore sleep control register */
|
||||||
REG_CPM_SCR = scr;
|
REG_CPM_SCR = scr;
|
||||||
@ -324,87 +80,18 @@ static int jz_pm_do_sleep(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put CPU to HIBERNATE mode */
|
|
||||||
int jz_pm_hibernate(void)
|
|
||||||
{
|
|
||||||
printk("Put CPU into hibernate mode.\n");
|
|
||||||
return jz_pm_do_hibernate();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef CONFIG_JZ_POWEROFF
|
|
||||||
static irqreturn_t pm_irq_handler (int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Put CPU to SLEEP mode */
|
|
||||||
int jz_pm_sleep(void)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
#ifndef CONFIG_JZ_POWEROFF
|
|
||||||
if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
|
|
||||||
"PM", NULL))) {
|
|
||||||
printk ("PM could not get IRQ for GPIO_WAKEUP\n");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
printk("Put CPU into sleep mode.\n");
|
|
||||||
retval = jz_pm_do_sleep();
|
|
||||||
|
|
||||||
#ifndef CONFIG_JZ_POWEROFF
|
|
||||||
free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* valid states, only support standby(sleep) and mem(hibernate)
|
|
||||||
*/
|
|
||||||
static int jz_pm_valid(suspend_state_t state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case PM_SUSPEND_STANDBY:
|
|
||||||
case PM_SUSPEND_MEM:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Jz CPU enter save power mode
|
|
||||||
*/
|
|
||||||
static int jz_pm_enter(suspend_state_t state)
|
|
||||||
{
|
|
||||||
if (state == PM_SUSPEND_STANDBY)
|
|
||||||
jz_pm_sleep();
|
|
||||||
else
|
|
||||||
jz_pm_hibernate();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct platform_suspend_ops jz_pm_ops = {
|
static struct platform_suspend_ops jz_pm_ops = {
|
||||||
.valid = jz_pm_valid,
|
.valid = suspend_valid_only_mem,
|
||||||
.enter = jz_pm_enter,
|
.enter = jz_pm_enter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize power interface
|
* Initialize power interface
|
||||||
*/
|
*/
|
||||||
int __init jz_pm_init(void)
|
int __init jz_pm_init(void)
|
||||||
{
|
{
|
||||||
printk("Power Management for JZ\n");
|
|
||||||
|
|
||||||
suspend_set_ops(&jz_pm_ops);
|
suspend_set_ops(&jz_pm_ops);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
late_initcall(jz_pm_init);
|
||||||
//module_init(jz_pm_init);
|
|
||||||
|
|
||||||
|
@ -174,9 +174,6 @@ void __init plat_mem_setup(void)
|
|||||||
_machine_restart = jz_restart;
|
_machine_restart = jz_restart;
|
||||||
_machine_halt = jz_halt;
|
_machine_halt = jz_halt;
|
||||||
pm_power_off = jz_power_off;
|
pm_power_off = jz_power_off;
|
||||||
#ifdef CONFIG_PM
|
|
||||||
jz_pm_init();
|
|
||||||
#endif
|
|
||||||
jz_soc_setup();
|
jz_soc_setup();
|
||||||
jz_serial_setup();
|
jz_serial_setup();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user