[PATCH wireless-next v3 18/33] wifi: mm81x: add ps.c
From: Lachlan Hodges <hidden>
Date: 2026-06-26 06:32:21
Also in:
lkml
Subsystem:
networking drivers (wireless), the rest · Maintainers:
Johannes Berg, Linus Torvalds
(Patches split per file for review, will be a single commit alongside SDIO ids once review is complete. See cover letter for more information) Signed-off-by: Lachlan Hodges <redacted> --- drivers/net/wireless/morsemicro/mm81x/ps.c | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 drivers/net/wireless/morsemicro/mm81x/ps.c
diff --git a/drivers/net/wireless/morsemicro/mm81x/ps.c b/drivers/net/wireless/morsemicro/mm81x/ps.c
new file mode 100644
index 000000000000..ab67823452ee
--- /dev/null
+++ b/drivers/net/wireless/morsemicro/mm81x/ps.c@@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2026 Morse Micro + */ +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include "hif.h" +#include "skbq.h" +#include "mac.h" +#include "bus.h" +#include "ps.h" + +static void mm81x_ps_wakeup(struct mm81x_ps *mps) +{ + struct mm81x *mors = container_of(mps, struct mm81x, ps); + + if (!mps->enable || !mps->suspended) + return; + + mm81x_set_bus_enable(mors, true); + mps->suspended = false; +} + +static void mm81x_ps_sleep(struct mm81x_ps *mps) +{ + struct mm81x *mors = container_of(mps, struct mm81x, ps); + + if (!mps->enable || mps->suspended) + return; + + mps->suspended = true; + mm81x_set_bus_enable(mors, false); +} + +static void mm81x_ps_evaluate(struct mm81x_ps *mps) +{ + struct mm81x *mors = container_of(mps, struct mm81x, ps); + bool needs_wake = false; + unsigned long flags_on_entry = + (mors->hif.event_flags & + ~BIT(MM81X_HIF_EVT_DATA_TRAFFIC_PAUSE_PEND)); + + if (!mps->enable) + return; + + needs_wake = (mps->wakers > 0); + needs_wake |= (flags_on_entry > 0); + needs_wake |= (mm81x_hif_get_tx_buffered_count(mors) > 0); + + if (needs_wake) { + mm81x_ps_wakeup(mps); + return; + } + + mm81x_ps_sleep(mps); +} + +static void mm81x_ps_evaluate_work(struct work_struct *work) +{ + struct mm81x_ps *mps = + container_of(work, struct mm81x_ps, delayed_eval_work.work); + + if (mps->enable) { + mutex_lock(&mps->lock); + mm81x_ps_evaluate(mps); + mutex_unlock(&mps->lock); + } +} + +void mm81x_ps_enable(struct mm81x *mors) +{ + struct mm81x_ps *mps = &mors->ps; + + if (mps->enable) { + mutex_lock(&mps->lock); + if (mps->wakers == 0) { + WARN_ON_ONCE(1); + } else { + mps->wakers--; + mm81x_ps_evaluate(mps); + } + mutex_unlock(&mps->lock); + } +} + +void mm81x_ps_disable(struct mm81x *mors) +{ + struct mm81x_ps *mps = &mors->ps; + + if (mps->enable) { + mutex_lock(&mps->lock); + mps->wakers++; + mm81x_ps_evaluate(mps); + mutex_unlock(&mps->lock); + } +} + +int mm81x_ps_init(struct mm81x *mors) +{ + struct mm81x_ps *mps = &mors->ps; + + mps->enable = (mors->bus_type == MM81X_BUS_TYPE_USB); + mps->suspended = true; + mps->wakers = 1; /* we default to being on */ + mutex_init(&mps->lock); + INIT_DELAYED_WORK(&mps->delayed_eval_work, mm81x_ps_evaluate_work); + + return 0; +} + +void mm81x_ps_finish(struct mm81x *mors) +{ + struct mm81x_ps *mps = &mors->ps; + + if (mps->enable) { + mps->enable = false; + cancel_delayed_work_sync(&mps->delayed_eval_work); + } +}
--
2.43.0