[PATCH wireless-next 3/4] wifi: cw1200: handle the XR819 channel switch and join

From: Pablo Mazzini

Date: Mon Nov 02 2026 - 14:24:49 EST


The XR819, detected as CW1x60, asserts on SWITCH_CHANNEL while idle
and only joins synchronously, confirming after up to 5 s. Keep the
channel for scan and join, as the vendor driver does, drop the
asynchronous join flags, and allow 7 s for the join.

Signed-off-by: Pablo Mazzini <pmazzini@xxxxxxxxx>
---
drivers/net/wireless/st/cw1200/fwio.c | 2 ++
drivers/net/wireless/st/cw1200/fwio.h | 2 ++
drivers/net/wireless/st/cw1200/sta.c | 8 +++++---
drivers/net/wireless/st/cw1200/wsm.c | 3 ++-
4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c
index 6601aec1f231..1a68ef6ed2fa 100644
--- a/drivers/net/wireless/st/cw1200/fwio.c
+++ b/drivers/net/wireless/st/cw1200/fwio.c
@@ -69,6 +69,8 @@ static const struct cw1200_chip cw1200_chips[] = {
.revision = CW1X60_HW_REV,
.firmware = FIRMWARE_CW1X60,
.sdd = SDD_FILE_CW1X60,
+ .sync_join = true,
+ .no_switch_channel = true,
},
};

diff --git a/drivers/net/wireless/st/cw1200/fwio.h b/drivers/net/wireless/st/cw1200/fwio.h
index e97cbcd54e57..9925d4bcedda 100644
--- a/drivers/net/wireless/st/cw1200/fwio.h
+++ b/drivers/net/wireless/st/cw1200/fwio.h
@@ -30,6 +30,8 @@ struct cw1200_chip {
int revision;
const char *firmware;
const char *sdd;
+ bool sync_join; /* no asynchronous join */
+ bool no_switch_channel; /* scan and join pass the channel */
};

int cw1200_load_firmware(struct cw1200_common *priv);
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index f3f31aa52499..eeb2bf56edff 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -349,8 +349,10 @@ int cw1200_config(struct ieee80211_hw *dev, int radio_idx, u32 changed)
pr_debug("[STA] Freq %d (wsm ch: %d).\n",
ch->center_freq, ch->hw_value);

- /* __cw1200_flush() implicitly locks tx, if successful */
- if (!__cw1200_flush(priv, false)) {
+ if (priv->chip->no_switch_channel) {
+ priv->channel = ch;
+ } else if (!__cw1200_flush(priv, false)) {
+ /* __cw1200_flush() implicitly locks tx, if successful */
if (!wsm_switch_channel(priv, &channel)) {
ret = wait_event_timeout(priv->channel_switch_done,
!priv->channel_switch_in_progress,
@@ -1304,7 +1306,7 @@ static void cw1200_do_join(struct cw1200_common *priv)
}

/* Enable asynchronous join calls */
- if (!priv->vif->cfg.ibss_joined) {
+ if (!priv->vif->cfg.ibss_joined && !priv->chip->sync_join) {
join.flags |= WSM_JOIN_FLAGS_FORCE;
join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND;
}
diff --git a/drivers/net/wireless/st/cw1200/wsm.c b/drivers/net/wireless/st/cw1200/wsm.c
index d6529e5b73b2..6b0b333620ee 100644
--- a/drivers/net/wireless/st/cw1200/wsm.c
+++ b/drivers/net/wireless/st/cw1200/wsm.c
@@ -20,6 +20,7 @@
#include "debug.h"

#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */
+#define WSM_CMD_JOIN_TIMEOUT (7 * HZ) /* A synchronous join takes up to 5 s */
#define WSM_CMD_START_TIMEOUT (7 * HZ)
#define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */
#define WSM_CMD_MAX_TIMEOUT (3 * HZ)
@@ -445,7 +446,7 @@ int wsm_join(struct cw1200_common *priv, struct wsm_join *arg)

priv->tx_burst_idx = -1;
ret = wsm_cmd_send(priv, buf, &resp,
- WSM_JOIN_REQ_ID, WSM_CMD_TIMEOUT);
+ WSM_JOIN_REQ_ID, WSM_CMD_JOIN_TIMEOUT);
/* TODO: Update state based on resp.min|max_power_level */

priv->join_complete_status = resp.status;
--
2.52.0