1: 在设备sleep之后,如tp,会低概率出现触发中断函数之后,读ic寄存器失败,可能会导致黑屏死机。
因为总线(如i2c, spi…)没及时醒来,而中断优先级比较高,导致喂狗超时。为了解决这个问题,
可在系统sleep/wake up时置位flag,待bus ready之后,再做通信。我称为间接法。
1.1:
pm.h
/**
xxx_tp_driver.c
static DECLARE_WAIT_QUEUE_HEAD(waiter);
void tp_i2c_suspend(struct touchpanel_data *ts)
{
ts->i2c_ready = false; //suspend时flag
if (ts->black_gesture_support ) {
enable_irq_wake(ts->irq);
return;
}
disable_irq(ts->irq);
}
void tp_i2c_resume(struct touchpanel_data *ts)
{
if (ts->black_gesture_support) {
disable_irq_wake(ts->irq);
goto OUT;
}
enable_irq(ts->irq);
OUT:
ts->i2c_ready = true; //resume时flag
if (ts->black_gesture_support) {
wake_up_interruptible(&waiter); //如果bus resume ok, 唤醒waiter中的等候线程
}
}
static int tp_spi_suspend(struct device *dev)
{
…
tp_i2c_suspend(ts);
return 0;
}
static int tp_spi_resume(struct device *dev)
{
…
tp_i2c_resume(ts);
return 0;
}
static const struct dev_pm_ops tp_pm_ops = {
#ifdef CONFIG_FB
.suspend = tp_spi_suspend, //系统sleep之前,回调本函数
.resume = tp_spi_resume, //系统wake之后,回调本函数
#endif
};
static struct spi_driver tp_spi_driver = {
.driver = {
.name = TP_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = tp_match_table_all,
.pm = &tp_pm_ops, //将dev注册到pm subsystem中
},
};
static irqreturn_t tp_irq_thread_fn(int irq, void *dev_id)
{
…
if (ts->i2c_ready == false) {
//TPD_INFO(“Wait device resume!”);
wait_event_interruptible_timeout(waiter,
ts->i2c_ready,
msecs_to_jiffies(1000)); //如果bus还在休眠中,加入waiter等待队列,最长等待1s
//please refer to wait_
//TPD_INFO(“Device maybe resume!”);
}
if (ts->i2c_ready == false) {
TPD_INFO(“The device not resume 1000ms!”); //如果1s后bus还sleep状态,直接退出irq_fn。
return IRQ_HANDLED;
}
…
}
ret = request_threaded_irq(ts->irq, NULL,
tp_irq_thread_fn,
ts->irq_flags | IRQF_ONESHOT,
TPD_DEVICE, ts);
1.2:如果中断处理函数比较长,有没有可能在中断处理过程中bus又睡下去了?回答是有可能。那如何
来规避这个问题呢?
struct wakeup_source *gesture_process_ws;
ws = wakeup_source_register(“xxx_wakelock”); //please refer to
__pm_stay_awake(ws); //在中断流程的入口设置保持wake标记
__pm_relax(ws); //中断结束的地方释放
2:直接控制pm的方法:
也就是把pm_runtime_enable/disable从resume_early/suspend_late转移到noirq流程中
/drivers/base/power/main.c
static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
{
…
Out:
pm_runtime_enable(dev); //add
complete_all(&dev->powerpletion);
TRACE_RESUME(error);
return error;
}
static int device_resume_early(struct device *dev, pm_message_t state, bool async)
{
…
pm_runtime_enable(dev); //delete
complete_all(&dev->powerpletion);
return error;
}
static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback;
const char *info;
bool no_subsys_cb = false;
int error = 0;
TRACE_DEVICE(dev);
TRACE_SUSPEND(0);__pm_runtime_disable(dev, false); //add
…
}
static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback;
const char *info;
int error = 0;
TRACE_DEVICE(dev);
TRACE_SUSPEND(0);__pm_runtime_disable(dev, false); //delete
…
}
本文发布于:2024-01-28 02:18:39,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063795274077.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |