#include <brcmu_wifi.h>
 #include <brcmu_d11.h>
 
-static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
+static u16 d11n_sb(enum brcmu_chan_sb sb)
 {
-       ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK;
+       switch (sb) {
+       case BRCMU_CHAN_SB_NONE:
+               return BRCMU_CHSPEC_D11N_SB_N;
+       case BRCMU_CHAN_SB_L:
+               return BRCMU_CHSPEC_D11N_SB_L;
+       case BRCMU_CHAN_SB_U:
+               return BRCMU_CHSPEC_D11N_SB_U;
+       default:
+               WARN_ON(1);
+       }
+       return 0;
+}
 
-       switch (ch->bw) {
+static u16 d11n_bw(enum brcmu_chan_bw bw)
+{
+       switch (bw) {
        case BRCMU_CHAN_BW_20:
-               ch->chspec |= BRCMU_CHSPEC_D11N_BW_20 | BRCMU_CHSPEC_D11N_SB_N;
-               break;
+               return BRCMU_CHSPEC_D11N_BW_20;
        case BRCMU_CHAN_BW_40:
+               return BRCMU_CHSPEC_D11N_BW_40;
        default:
-               WARN_ON_ONCE(1);
-               break;
+               WARN_ON(1);
        }
+       return 0;
+}
 
+static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
+{
+       if (ch->bw == BRCMU_CHAN_BW_20)
+               ch->sb = BRCMU_CHAN_SB_NONE;
+
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
+                       BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
+                       0, d11n_sb(ch->sb));
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
+                       0, d11n_bw(ch->bw));
+
+       ch->chspec &= ~BRCMU_CHSPEC_D11N_BND_MASK;
        if (ch->chnum <= CH_MAX_2G_CHANNEL)
                ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
        else
                ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
 }
 
-static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
+static u16 d11ac_bw(enum brcmu_chan_bw bw)
 {
-       ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK;
-
-       switch (ch->bw) {
+       switch (bw) {
        case BRCMU_CHAN_BW_20:
-               ch->chspec |= BRCMU_CHSPEC_D11AC_BW_20;
-               break;
+               return BRCMU_CHSPEC_D11AC_BW_20;
        case BRCMU_CHAN_BW_40:
+               return BRCMU_CHSPEC_D11AC_BW_40;
        case BRCMU_CHAN_BW_80:
-       case BRCMU_CHAN_BW_80P80:
-       case BRCMU_CHAN_BW_160:
+               return BRCMU_CHSPEC_D11AC_BW_80;
        default:
-               WARN_ON_ONCE(1);
-               break;
+               WARN_ON(1);
        }
+       return 0;
+}
 
+static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
+{
+       if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
+               ch->sb = BRCMU_CHAN_SB_L;
+
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
+                       BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
+                       BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
+       brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
+                       0, d11ac_bw(ch->bw));
+
+       ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
        if (ch->chnum <= CH_MAX_2G_CHANNEL)
                ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
        else
        switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
        case BRCMU_CHSPEC_D11N_BW_20:
                ch->bw = BRCMU_CHAN_BW_20;
+               ch->sb = BRCMU_CHAN_SB_NONE;
                break;
        case BRCMU_CHSPEC_D11N_BW_40:
                ch->bw = BRCMU_CHAN_BW_40;
        switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
        case BRCMU_CHSPEC_D11AC_BW_20:
                ch->bw = BRCMU_CHAN_BW_20;
+               ch->sb = BRCMU_CHAN_SB_NONE;
                break;
        case BRCMU_CHSPEC_D11AC_BW_40:
                ch->bw = BRCMU_CHAN_BW_40;
                break;
        case BRCMU_CHSPEC_D11AC_BW_80:
                ch->bw = BRCMU_CHAN_BW_80;
+               ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
+                                        BRCMU_CHSPEC_D11AC_SB_SHIFT);
+               switch (ch->sb) {
+               case BRCMU_CHAN_SB_LL:
+                       ch->chnum -= CH_30MHZ_APART;
+                       break;
+               case BRCMU_CHAN_SB_LU:
+                       ch->chnum -= CH_10MHZ_APART;
+                       break;
+               case BRCMU_CHAN_SB_UL:
+                       ch->chnum += CH_10MHZ_APART;
+                       break;
+               case BRCMU_CHAN_SB_UU:
+                       ch->chnum += CH_30MHZ_APART;
+                       break;
+               default:
+                       WARN_ON_ONCE(1);
+                       break;
+               }
                break;
        case BRCMU_CHSPEC_D11AC_BW_8080:
        case BRCMU_CHSPEC_D11AC_BW_160: