diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h index 8ea8616572a4..7eaad27562d2 100644 --- a/include/soc/swr-wcd.h +++ b/include/soc/swr-wcd.h @@ -26,6 +26,7 @@ enum { SWR_CLK_FREQ, SWR_DEVICE_SSR_DOWN, SWR_DEVICE_SSR_UP, + SWR_REGISTER_WAKE_IRQ, }; struct swr_mstr_port { diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index df373abcc4db..64da45700409 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -1414,6 +1414,32 @@ handle_irq: return ret; } +static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev) +{ + struct swr_mstr_ctrl *swrm = dev; + int ret = IRQ_HANDLED; + + if (!swrm || !(swrm->dev)) { + pr_err("%s: swrm or dev is null\n", __func__); + return IRQ_NONE; + } + mutex_lock(&swrm->devlock); + if (!swrm->dev_up) { + if (swrm->wake_irq > 0) + disable_irq_nosync(swrm->wake_irq); + mutex_unlock(&swrm->devlock); + return ret; + } + mutex_unlock(&swrm->devlock); + if (swrm->wake_irq > 0) + disable_irq_nosync(swrm->wake_irq); + pm_runtime_get_sync(swrm->dev); + pm_runtime_mark_last_busy(swrm->dev); + pm_runtime_put_autosuspend(swrm->dev); + + return ret; +} + static void swrm_wakeup_work(struct work_struct *work) { struct swr_mstr_ctrl *swrm; @@ -1585,8 +1611,8 @@ static int swrm_event_notify(struct notifier_block *self, schedule_work(&(swrm->dc_presence_work)); break; case SWR_WAKE_IRQ_EVENT: - if (swrm->wakeup_req && !swrm->wakeup_triggered) { - swrm->wakeup_triggered = true; + if (swrm->ipc_wakeup && !swrm->ipc_wakeup_triggered) { + swrm->ipc_wakeup_triggered = true; schedule_work(&swrm->wakeup_work); } break; @@ -1762,6 +1788,8 @@ static int swrm_probe(struct platform_device *pdev) swrm->mclk_freq = MCLK_FREQ; swrm->dev_up = true; swrm->state = SWR_MSTR_UP; + swrm->ipc_wakeup = false; + swrm->ipc_wakeup_triggered = false; init_completion(&swrm->reset); init_completion(&swrm->broadcast); init_completion(&swrm->clk_off_complete); @@ -1789,11 +1817,6 @@ static int swrm_probe(struct platform_device *pdev) } } - if (of_property_read_u32(swrm->dev->of_node, - "qcom,swr-wakeup-required", &swrm->wakeup_req)) { - swrm->wakeup_req = false; - } - if (swrm->reg_irq) { ret = swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_REGISTER); @@ -1903,6 +1926,9 @@ static int swrm_remove(struct platform_device *pdev) swrm, SWR_IRQ_FREE); else if (swrm->irq) free_irq(swrm->irq, swrm); + else if (swrm->wake_irq > 0) + free_irq(swrm->wake_irq, swrm); + pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); swr_unregister_master(&swrm->master); @@ -1944,9 +1970,10 @@ static int swrm_runtime_resume(struct device *dev) if ((swrm->state == SWR_MSTR_DOWN) || (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) { - if (swrm->clk_stop_mode0_supp && swrm->wakeup_req) { - msm_aud_evt_blocking_notifier_call_chain( - SWR_WAKE_IRQ_DEREGISTER, (void *)swrm); + if (swrm->clk_stop_mode0_supp) { + if (swrm->ipc_wakeup) + msm_aud_evt_blocking_notifier_call_chain( + SWR_WAKE_IRQ_DEREGISTER, (void *)swrm); } if (swrm_clk_request(swrm, true)) @@ -2025,10 +2052,14 @@ static int swrm_runtime_suspend(struct device *dev) } swrm_clk_request(swrm, false); - if (swrm->clk_stop_mode0_supp && swrm->wakeup_req) { - msm_aud_evt_blocking_notifier_call_chain( - SWR_WAKE_IRQ_REGISTER, (void *)swrm); - swrm->wakeup_triggered = false; + if (swrm->clk_stop_mode0_supp) { + if (swrm->wake_irq > 0) { + enable_irq(swrm->wake_irq); + } else if (swrm->ipc_wakeup) { + msm_aud_evt_blocking_notifier_call_chain( + SWR_WAKE_IRQ_REGISTER, (void *)swrm); + swrm->ipc_wakeup_triggered = false; + } } } @@ -2064,6 +2095,35 @@ static int swrm_device_down(struct device *dev) return 0; } +int swrm_register_wake_irq(struct swr_mstr_ctrl *swrm) +{ + int ret = 0; + + if (!swrm->ipc_wakeup) { + swrm->wake_irq = platform_get_irq_byname(swrm->pdev, + "swr_wake_irq"); + if (swrm->wake_irq < 0) { + dev_err(swrm->dev, + "%s() error getting wake irq handle: %d\n", + __func__, swrm->wake_irq); + return -EINVAL; + } + + ret = request_threaded_irq(swrm->wake_irq, NULL, + swrm_wakeup_interrupt, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "swr_wake_irq", swrm); + if (ret) { + dev_err(swrm->dev, "%s: Failed to request irq %d\n", + __func__, ret); + return -EINVAL; + } + /* Disable wake irq - enable it after clock stop */ + disable_irq(swrm->wake_irq); + } + return ret; +} + /** * swrm_wcd_notify - parent device can notify to soundwire master through * this function @@ -2181,6 +2241,21 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) mutex_unlock(&swrm->mlock); } break; + case SWR_REGISTER_WAKE_IRQ: + if (!data) { + dev_err(swrm->dev, "%s: reg wake irq data is NULL\n", + __func__); + ret = -EINVAL; + } else { + mutex_lock(&swrm->mlock); + swrm->ipc_wakeup = *(u32 *)data; + ret = swrm_register_wake_irq(swrm); + if (ret) + dev_err(swrm->dev, "%s: register wake_irq failed\n", + __func__); + mutex_unlock(&swrm->mlock); + } + break; default: dev_err(swrm->dev, "%s: swr master unknown id %d\n", __func__, id); diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index 4a40fa339e7e..b3e358a0d944 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -131,6 +131,7 @@ struct swr_mstr_ctrl { int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq, void *data), void *swr_handle, int type); int irq; + int wake_irq; int version; int mclk_freq; u32 num_dev; @@ -152,9 +153,9 @@ struct swr_mstr_ctrl { int swr_irq; u32 clk_stop_mode0_supp; struct work_struct wakeup_work; - u32 wakeup_req; + u32 ipc_wakeup; bool dev_up; - bool wakeup_triggered; + bool ipc_wakeup_triggered; }; #endif /* _SWR_WCD_CTRL_H */