您的位置:首页 > 其它

s3c6410 休眠与唤醒笔记

2016-03-31 10:25 225 查看
1.s3c6410无法进入休眠

   执行echo mem > /sys/power/state后系统无法进行休眠 跟踪发生pm相关函数没有注册 修改arch/arm/plat-samsung/pm.c在最后加上

arch_initcall(s3c_pm_init);//modify by hclydao 20150406
初始化 同时修改如下两个变量

unsigned long s3c_irqwake_intmask	= 0xffff0fffL;//eint0-3 can resume
unsigned long s3c_irqwake_eintmask	= 0x0L;
设置唤醒中断 这样休眠后就可以通过设置的中断唤醒

2.s3c6410休眠与唤醒之rtc

    休眠后rtc会打印一个BUG信息 修改如下drivers/rtc/rtc-s3c.c

增加

static bool wake_en;//add by hclydao 20150522
修改suspend和resume函数

static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
/* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
}
s3c_rtc_enable(pdev, 0);
#if 0 //modify by hclydao 20150507
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(s3c_rtc_alarmno);
#else
if (device_may_wakeup(&pdev->dev) && !wake_en)
if(enable_irq_wake(s3c_rtc_alarmno) == 0)
wake_en = true;
else
dev_err(&pdev->dev,"enable_irq_wake failed\n");
#endif
return 0;
}

static int s3c_rtc_resume(struct platform_device *pdev)
{
unsigned int tmp;
s3c_rtc_enable(pdev, 1);
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
}
#if 0 //modify by hclydao 20150507
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(s3c_rtc_alarmno);
#else
if (device_may_wakeup(&pdev->dev) && wake_en) {
disable_irq_wake(s3c_rtc_alarmno);
wake_en = false;
}
#endif
return 0;
}
不通过rtc唤醒

3.s3c6410 休眠与唤醒之lcd

echo mem > /sys/power/state休眠后 唤醒 lcd显示为白屏 修改如下

drivers/video/samsung/s3cfb_fimd4x.c中的s3cfb_set_gpio函数在最前面修改如下本身也有说明 这个寄存器要设置成0

#if	1
/* See mach-smdk6410.c:smdk6410_map_io() - S3C64XX_MODEM_MIFPCON */
/* Must be '0' for Normal-path instead of By-pass */
//writel(0x0, S3C_HOSTIFB_MIFPCON);
val = __raw_readl(S3C64XX_MODEM_MIFPCON); //add by hclydao 20150526
val &= ~MIFPCON_LCD_BYPASS;
__raw_writel(val, S3C64XX_MODEM_MIFPCON);
#endif
这里修改后 白屏问题解决 但是唤醒后是黑屏 要点击一下屏幕才会有界面显示出来 同时有一些区域还是显示的是黑色

跟踪发现里面执行fbcon_switch lcd休眠的时候切换了控制台 导致fb数据被清空 去现虚拟控制台后发现lcd完全没显示 所以接到源头

kernel/power/suspend.c 中suspend_prepare函数调用了pm_prepare_console以及pm_restore_console把这两个注释掉 解决问题

4.s3c6410 休眠与唤醒之nandflash

休眠唤醒后 往flash里写数据 重新开机后发现数据没有保存 跟踪到代码drivers/mtd/nand/s3c_nand.c

里面有suspend和resume函数 加入打印flash寄存器代码 发现两次打印的flash寄存器值不一样 修改如下

#include <plat/pm.h> //add by hclydao 20150528
static int nand_regs[] = {//add by hclydao 20150528
S3C_NFCONF,
S3C_NFCONT,
S3C_NFCMMD,
S3C_NFADDR,
};

static long nand_value[ARRAY_SIZE(nand_regs)];//add by hclydao 20150528

static void s3c_nand_pm(int state) {//add by hclydao 20150528
int i;
if(state) {
for(i=0;i<ARRAY_SIZE(nand_regs);i++) {
nand_value[i] = readl(s3c_nand.regs + nand_regs[i]);
}
} else {
for(i=0;i<ARRAY_SIZE(nand_regs);i++) {
writel(nand_value[i], (s3c_nand.regs + nand_regs[i]));
}
}
}

static void print_nand() { //add by hclydao 20150528
printk("+++++++%s : nfconf is 0x%x cont is 0x%x cmmd is 0x%x nfaddr is 0x%x\n",__func__,
readl(s3c_nand.regs+S3C_NFCONF),readl(s3c_nand.regs+S3C_NFCONT),
readl(s3c_nand.regs+S3C_NFCMMD),readl(s3c_nand.regs+S3C_NFADDR));
}

static int s3c_nand_suspend(struct platform_device *dev, pm_message_t pm)
{
struct s3c_nand *info = platform_get_drvdata(dev);
s3c_nand_pm(1); //add by hclydao 20150528
//print_nand();
//s3c_pm_do_save(s3c_nand_save, ARRAY_SIZE(s3c_nand_save));
clk_disable(s3c_nand.clk);
return 0;
}

static int s3c_nand_resume(struct platform_device *dev)
{
struct s3c_nand *info = platform_get_drvdata(dev);
//s3c_pm_do_restore(s3c_nand_save, ARRAY_SIZE(s3c_nand_save));
s3c_nand_pm(0); //add by hclydao 20150528
//print_nand();
clk_enable(s3c_nand.clk);
return 0;
}
编译下载 正常 问题解决

5. s3c6410休眠与唤醒之wm8960

    最初测试中发现唤醒后无法播放声音,量波型发现 i2s 时钟信号正常 数据信号没有 没有数据发送给wm8960 跟踪发现 唤醒后播放声音dma没有产生中断 偏移地址没有发生变化 导致数据传送失败  本来想通过sound/soc/samsung/dma.c中的dma_trigger去实现dmac数据保存与恢复 跟踪发现suspend信号根本都没有发到这里来 跟踪半天 找到了源头 但是无法解决 所以直接在sound/soc/samsung/i2s.c里加了算了 修改如下

#ifdef CONFIG_PM
#include <asm/hardware/pl080.h>//add by hclydao 20150601
static int dma_regs[] = { //add by hclydao 20150601
PL080_TC_CLEAR,
PL080_ERR_CLEAR,
PL080_SOFT_BREQ,
PL080_SOFT_SREQ,
PL080_CONFIG,
PL080_SYNC,
};

static long dma_value0[ARRAY_SIZE(dma_regs)];//add by hclydao 20150601
static long dma_value1[ARRAY_SIZE(dma_regs)];//add by hclydao 20150601

void s3c_pm_save_dma(void) {//add by hclydao 20150601
void __iomem *regs;
int i = 0;
regs = ioremap(0x75000000, 0x200);
if (!regs) {
printk(KERN_ERR "%s: %d failed to ioremap()\n", __func__,__LINE__);
return ;
}
for(i=0;i<ARRAY_SIZE(dma_regs);i++) {
dma_value0[i] = readl(regs + dma_regs[i]);
}
iounmap(regs);

regs = ioremap(0x75100000, 0x200);
if (!regs) {
printk(KERN_ERR "%s: %d failed to ioremap()\n", __func__,__LINE__);
return ;
}
for(i=0;i<ARRAY_SIZE(dma_regs);i++) {
dma_value1[i] = readl(regs + dma_regs[i]);
}

iounmap(regs);
return;
}

void s3c_pm_restore_dma(void) {//add by hclydao 20150601
void __iomem *regs;
int i = 0;
regs = ioremap(0x75000000, 0x200);
if (!regs) {
printk(KERN_ERR "%s: %d failed to ioremap()\n", __func__,__LINE__);
return ;
}

for(i=0;i<ARRAY_SIZE(dma_regs);i++) {
writel(dma_value0[i],(regs + dma_regs[i]));
}
iounmap(regs);

regs = ioremap(0x75100000, 0x200);
if (!regs) {
printk(KERN_ERR "%s: %d failed to ioremap()\n", __func__,__LINE__);
return ;
}

for(i=0;i<ARRAY_SIZE(dma_regs);i++) {
writel(dma_value1[i],(regs + dma_regs[i]));
}

iounmap(regs);
return;
}
static void i2s_printk(struct i2s_dai *i2s) { //add by hclydao 20150528
printk("++++I2SMOD is 0x%x I2SCON : 0x%x I2SPSR : 0x%x I2SFIC: 0x%x\n",readl(i2s->addr + I2SMOD),readl(i2s->addr + I2SCON),
readl(i2s->addr + I2SPSR),readl(i2s->addr + I2SFIC));
}

static int i2s_suspend(struct snd_soc_dai *dai)
{
struct i2s_dai *i2s = to_info(dai);
s3c_pm_save_dma();//add by hclydao 20150601
//if (dai->active) {//modify by hclydao 20150601
i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
i2s->suspend_i2sfic = readl(i2s->addr + I2SFIC);
//}

return 0;
}

static int i2s_resume(struct snd_soc_dai *dai)
{
struct i2s_dai *i2s = to_info(dai);
s3c_pm_restore_dma();//add by hclydao 20150601
//if (dai->active) {//modify by hclydao 20150601
writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
writel(i2s->suspend_i2sfic, i2s->addr + I2SFIC);
//}
return 0;
}
#else
#define i2s_suspend NULL
#define i2s_resume  NULL
#endif
将串口和pcm用的dmac保存再恢复 同时将i2s相关寄存器也作相应处理 还要修改sound/soc/codecs/wm8960.c

static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
#if 1 //modify by hclydao youhua 20150601
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);

wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
#endif
return 0;
}

static int wm8960_resume(struct snd_soc_codec *codec)
{

struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
#if 0 //modify by hclydao youhua 20150601
int i;
u8 data[2];
u16 *cache = codec->reg_cache;

/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
#else
wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
#endif
return 0;
}
还有一个系统控制选择dma还是sdma的地方arch/arm/mach-s3c64xx/pm.c在static struct sleep_save core_save[]最后加上

SAVE_ITEM(S3C_SYSREG(0x110)),//add by hclydao 20150529
编译下载 问题解决

6.s3c6410休眠与唤醒之usb host

唤醒后usb host无法工作 修改如下

drivers/usb/host/ohci-s3c2410.c

#ifdef	CONFIG_PM //add by hclydao 20150522
static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
{
#ifdef CONFIG_MACH_GZSD6410
s3c_otg_phy_config(0);
#endif
}

static int ohci_hcd_s3c2410_drv_resume(struct device *dev)
{
#ifdef CONFIG_MACH_GZSD6410
s3c_otg_phy_config(1);
#endif
}
#endif
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe		= ohci_hcd_s3c2410_drv_probe,
.remove		= ohci_hcd_s3c2410_drv_remove,
.shutdown	= usb_hcd_platform_shutdown,
#if 0 //modify by hclydao 20150522
/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */
/*.resume	= ohci_hcd_s3c2410_drv_resume, */
#else
#ifdef	CONFIG_PM
.suspend	= ohci_hcd_s3c2410_drv_suspend,
.resume	= ohci_hcd_s3c2410_drv_resume,
#endif
#endif
.driver		= {
.owner	= THIS_MODULE,
.name	= "s3c2410-ohci",
},
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: