s3c6410 休眠与唤醒笔记

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",
	},
};


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值