1 /*
2  * Copyright (c) 2013 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 /*********************channel spec common functions*********************/
17 
18 #include <linux/module.h>
19 
20 #include <brcmu_utils.h>
21 #include <brcmu_wifi.h>
22 #include <brcmu_d11.h>
23 
24 static u16 d11n_sb(enum brcmu_chan_sb sb)
25 {
26 	switch (sb) {
27 	case BRCMU_CHAN_SB_NONE:
28 		return BRCMU_CHSPEC_D11N_SB_N;
29 	case BRCMU_CHAN_SB_L:
30 		return BRCMU_CHSPEC_D11N_SB_L;
31 	case BRCMU_CHAN_SB_U:
32 		return BRCMU_CHSPEC_D11N_SB_U;
33 	default:
34 		WARN_ON(1);
35 	}
36 	return 0;
37 }
38 
39 static u16 d11n_bw(enum brcmu_chan_bw bw)
40 {
41 	switch (bw) {
42 	case BRCMU_CHAN_BW_20:
43 		return BRCMU_CHSPEC_D11N_BW_20;
44 	case BRCMU_CHAN_BW_40:
45 		return BRCMU_CHSPEC_D11N_BW_40;
46 	default:
47 		WARN_ON(1);
48 	}
49 	return 0;
50 }
51 
52 static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
53 {
54 	if (ch->bw == BRCMU_CHAN_BW_20)
55 		ch->sb = BRCMU_CHAN_SB_NONE;
56 
57 	ch->chspec = 0;
58 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
59 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
60 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
61 			0, d11n_sb(ch->sb));
62 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
63 			0, d11n_bw(ch->bw));
64 
65 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
66 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
67 	else
68 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
69 }
70 
71 static u16 d11ac_bw(enum brcmu_chan_bw bw)
72 {
73 	switch (bw) {
74 	case BRCMU_CHAN_BW_20:
75 		return BRCMU_CHSPEC_D11AC_BW_20;
76 	case BRCMU_CHAN_BW_40:
77 		return BRCMU_CHSPEC_D11AC_BW_40;
78 	case BRCMU_CHAN_BW_80:
79 		return BRCMU_CHSPEC_D11AC_BW_80;
80 	default:
81 		WARN_ON(1);
82 	}
83 	return 0;
84 }
85 
86 static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
87 {
88 	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
89 		ch->sb = BRCMU_CHAN_SB_L;
90 
91 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
92 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
93 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
94 			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
95 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
96 			0, d11ac_bw(ch->bw));
97 
98 	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
99 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
100 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
101 	else
102 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
103 }
104 
105 static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
106 {
107 	u16 val;
108 
109 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
110 	ch->control_ch_num = ch->chnum;
111 
112 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
113 	case BRCMU_CHSPEC_D11N_BW_20:
114 		ch->bw = BRCMU_CHAN_BW_20;
115 		ch->sb = BRCMU_CHAN_SB_NONE;
116 		break;
117 	case BRCMU_CHSPEC_D11N_BW_40:
118 		ch->bw = BRCMU_CHAN_BW_40;
119 		val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
120 		if (val == BRCMU_CHSPEC_D11N_SB_L) {
121 			ch->sb = BRCMU_CHAN_SB_L;
122 			ch->control_ch_num -= CH_10MHZ_APART;
123 		} else {
124 			ch->sb = BRCMU_CHAN_SB_U;
125 			ch->control_ch_num += CH_10MHZ_APART;
126 		}
127 		break;
128 	default:
129 		WARN_ON_ONCE(1);
130 		break;
131 	}
132 
133 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
134 	case BRCMU_CHSPEC_D11N_BND_5G:
135 		ch->band = BRCMU_CHAN_BAND_5G;
136 		break;
137 	case BRCMU_CHSPEC_D11N_BND_2G:
138 		ch->band = BRCMU_CHAN_BAND_2G;
139 		break;
140 	default:
141 		WARN_ON_ONCE(1);
142 		break;
143 	}
144 }
145 
146 static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
147 {
148 	u16 val;
149 
150 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
151 	ch->control_ch_num = ch->chnum;
152 
153 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
154 	case BRCMU_CHSPEC_D11AC_BW_20:
155 		ch->bw = BRCMU_CHAN_BW_20;
156 		ch->sb = BRCMU_CHAN_SB_NONE;
157 		break;
158 	case BRCMU_CHSPEC_D11AC_BW_40:
159 		ch->bw = BRCMU_CHAN_BW_40;
160 		val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
161 		if (val == BRCMU_CHSPEC_D11AC_SB_L) {
162 			ch->sb = BRCMU_CHAN_SB_L;
163 			ch->control_ch_num -= CH_10MHZ_APART;
164 		} else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
165 			ch->sb = BRCMU_CHAN_SB_U;
166 			ch->control_ch_num += CH_10MHZ_APART;
167 		} else {
168 			WARN_ON_ONCE(1);
169 		}
170 		break;
171 	case BRCMU_CHSPEC_D11AC_BW_80:
172 		ch->bw = BRCMU_CHAN_BW_80;
173 		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
174 					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
175 		switch (ch->sb) {
176 		case BRCMU_CHAN_SB_LL:
177 			ch->control_ch_num -= CH_30MHZ_APART;
178 			break;
179 		case BRCMU_CHAN_SB_LU:
180 			ch->control_ch_num -= CH_10MHZ_APART;
181 			break;
182 		case BRCMU_CHAN_SB_UL:
183 			ch->control_ch_num += CH_10MHZ_APART;
184 			break;
185 		case BRCMU_CHAN_SB_UU:
186 			ch->control_ch_num += CH_30MHZ_APART;
187 			break;
188 		default:
189 			WARN_ON_ONCE(1);
190 			break;
191 		}
192 		break;
193 	case BRCMU_CHSPEC_D11AC_BW_8080:
194 	case BRCMU_CHSPEC_D11AC_BW_160:
195 	default:
196 		WARN_ON_ONCE(1);
197 		break;
198 	}
199 
200 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
201 	case BRCMU_CHSPEC_D11AC_BND_5G:
202 		ch->band = BRCMU_CHAN_BAND_5G;
203 		break;
204 	case BRCMU_CHSPEC_D11AC_BND_2G:
205 		ch->band = BRCMU_CHAN_BAND_2G;
206 		break;
207 	default:
208 		WARN_ON_ONCE(1);
209 		break;
210 	}
211 }
212 
213 void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
214 {
215 	if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
216 		d11inf->encchspec = brcmu_d11n_encchspec;
217 		d11inf->decchspec = brcmu_d11n_decchspec;
218 	} else {
219 		d11inf->encchspec = brcmu_d11ac_encchspec;
220 		d11inf->decchspec = brcmu_d11ac_decchspec;
221 	}
222 }
223 EXPORT_SYMBOL(brcmu_d11_attach);
224