xref: /openbmc/linux/drivers/net/wireless/ti/wl12xx/cmd.c (revision 4f3db074)
1 /*
2  * This file is part of wl12xx
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation
5  * Copyright (C) 2011 Texas Instruments Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  */
22 
23 #include "../wlcore/cmd.h"
24 #include "../wlcore/debug.h"
25 
26 #include "wl12xx.h"
27 #include "cmd.h"
28 
29 int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
30 {
31 	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
32 	struct wl12xx_priv *priv = wl->priv;
33 	struct wl12xx_conf_rf *rf = &priv->conf.rf;
34 	int ret;
35 
36 	if (!wl->nvs)
37 		return -ENODEV;
38 
39 	ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
40 	if (!ext_radio_parms)
41 		return -ENOMEM;
42 
43 	ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
44 
45 	memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
46 	       rf->tx_per_channel_power_compensation_2,
47 	       CONF_TX_PWR_COMPENSATION_LEN_2);
48 	memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
49 	       rf->tx_per_channel_power_compensation_5,
50 	       CONF_TX_PWR_COMPENSATION_LEN_5);
51 
52 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
53 		    ext_radio_parms, sizeof(*ext_radio_parms));
54 
55 	ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
56 	if (ret < 0)
57 		wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
58 
59 	kfree(ext_radio_parms);
60 	return ret;
61 }
62 
63 int wl1271_cmd_general_parms(struct wl1271 *wl)
64 {
65 	struct wl1271_general_parms_cmd *gen_parms;
66 	struct wl1271_ini_general_params *gp =
67 		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
68 	struct wl12xx_priv *priv = wl->priv;
69 	bool answer = false;
70 	int ret;
71 
72 	if (!wl->nvs)
73 		return -ENODEV;
74 
75 	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
76 		wl1271_warning("FEM index from INI out of bounds");
77 		return -EINVAL;
78 	}
79 
80 	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
81 	if (!gen_parms)
82 		return -ENOMEM;
83 
84 	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
85 
86 	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
87 
88 	/* If we started in PLT FEM_DETECT mode, force auto detect */
89 	if (wl->plt_mode == PLT_FEM_DETECT)
90 		gen_parms->general_params.tx_bip_fem_auto_detect = true;
91 
92 	if (gen_parms->general_params.tx_bip_fem_auto_detect)
93 		answer = true;
94 
95 	/* Override the REF CLK from the NVS with the one from platform data */
96 	gen_parms->general_params.ref_clock = priv->ref_clock;
97 
98 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
99 	if (ret < 0) {
100 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
101 		goto out;
102 	}
103 
104 	gp->tx_bip_fem_manufacturer =
105 		gen_parms->general_params.tx_bip_fem_manufacturer;
106 
107 	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
108 		wl1271_warning("FEM index from FW out of bounds");
109 		ret = -EINVAL;
110 		goto out;
111 	}
112 
113 	/* If we are in calibrator based fem auto detect - save fem nr */
114 	if (wl->plt_mode == PLT_FEM_DETECT)
115 		wl->fem_manuf = gp->tx_bip_fem_manufacturer;
116 
117 	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
118 		answer == false ?
119 			"manual" :
120 		wl->plt_mode == PLT_FEM_DETECT ?
121 			"calibrator_fem_detect" :
122 			"auto",
123 		gp->tx_bip_fem_manufacturer);
124 
125 out:
126 	kfree(gen_parms);
127 	return ret;
128 }
129 
130 int wl128x_cmd_general_parms(struct wl1271 *wl)
131 {
132 	struct wl128x_general_parms_cmd *gen_parms;
133 	struct wl128x_ini_general_params *gp =
134 		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
135 	struct wl12xx_priv *priv = wl->priv;
136 	bool answer = false;
137 	int ret;
138 
139 	if (!wl->nvs)
140 		return -ENODEV;
141 
142 	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
143 		wl1271_warning("FEM index from ini out of bounds");
144 		return -EINVAL;
145 	}
146 
147 	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
148 	if (!gen_parms)
149 		return -ENOMEM;
150 
151 	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
152 
153 	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
154 
155 	/* If we started in PLT FEM_DETECT mode, force auto detect */
156 	if (wl->plt_mode == PLT_FEM_DETECT)
157 		gen_parms->general_params.tx_bip_fem_auto_detect = true;
158 
159 	if (gen_parms->general_params.tx_bip_fem_auto_detect)
160 		answer = true;
161 
162 	/* Replace REF and TCXO CLKs with the ones from platform data */
163 	gen_parms->general_params.ref_clock = priv->ref_clock;
164 	gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock;
165 
166 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
167 	if (ret < 0) {
168 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
169 		goto out;
170 	}
171 
172 	gp->tx_bip_fem_manufacturer =
173 		gen_parms->general_params.tx_bip_fem_manufacturer;
174 
175 	if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
176 		wl1271_warning("FEM index from FW out of bounds");
177 		ret = -EINVAL;
178 		goto out;
179 	}
180 
181 	/* If we are in calibrator based fem auto detect - save fem nr */
182 	if (wl->plt_mode == PLT_FEM_DETECT)
183 		wl->fem_manuf = gp->tx_bip_fem_manufacturer;
184 
185 	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
186 		answer == false ?
187 			"manual" :
188 		wl->plt_mode == PLT_FEM_DETECT ?
189 			"calibrator_fem_detect" :
190 			"auto",
191 		gp->tx_bip_fem_manufacturer);
192 
193 out:
194 	kfree(gen_parms);
195 	return ret;
196 }
197 
198 int wl1271_cmd_radio_parms(struct wl1271 *wl)
199 {
200 	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
201 	struct wl1271_radio_parms_cmd *radio_parms;
202 	struct wl1271_ini_general_params *gp = &nvs->general_params;
203 	int ret, fem_idx;
204 
205 	if (!wl->nvs)
206 		return -ENODEV;
207 
208 	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
209 	if (!radio_parms)
210 		return -ENOMEM;
211 
212 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
213 
214 	fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
215 
216 	/* 2.4GHz parameters */
217 	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
218 	       sizeof(struct wl1271_ini_band_params_2));
219 	memcpy(&radio_parms->dyn_params_2,
220 	       &nvs->dyn_radio_params_2[fem_idx].params,
221 	       sizeof(struct wl1271_ini_fem_params_2));
222 
223 	/* 5GHz parameters */
224 	memcpy(&radio_parms->static_params_5,
225 	       &nvs->stat_radio_params_5,
226 	       sizeof(struct wl1271_ini_band_params_5));
227 	memcpy(&radio_parms->dyn_params_5,
228 	       &nvs->dyn_radio_params_5[fem_idx].params,
229 	       sizeof(struct wl1271_ini_fem_params_5));
230 
231 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
232 		    radio_parms, sizeof(*radio_parms));
233 
234 	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
235 	if (ret < 0)
236 		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
237 
238 	kfree(radio_parms);
239 	return ret;
240 }
241 
242 int wl128x_cmd_radio_parms(struct wl1271 *wl)
243 {
244 	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
245 	struct wl128x_radio_parms_cmd *radio_parms;
246 	struct wl128x_ini_general_params *gp = &nvs->general_params;
247 	int ret, fem_idx;
248 
249 	if (!wl->nvs)
250 		return -ENODEV;
251 
252 	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
253 	if (!radio_parms)
254 		return -ENOMEM;
255 
256 	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
257 
258 	fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
259 
260 	/* 2.4GHz parameters */
261 	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
262 	       sizeof(struct wl128x_ini_band_params_2));
263 	memcpy(&radio_parms->dyn_params_2,
264 	       &nvs->dyn_radio_params_2[fem_idx].params,
265 	       sizeof(struct wl128x_ini_fem_params_2));
266 
267 	/* 5GHz parameters */
268 	memcpy(&radio_parms->static_params_5,
269 	       &nvs->stat_radio_params_5,
270 	       sizeof(struct wl128x_ini_band_params_5));
271 	memcpy(&radio_parms->dyn_params_5,
272 	       &nvs->dyn_radio_params_5[fem_idx].params,
273 	       sizeof(struct wl128x_ini_fem_params_5));
274 
275 	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
276 
277 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
278 		    radio_parms, sizeof(*radio_parms));
279 
280 	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
281 	if (ret < 0)
282 		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
283 
284 	kfree(radio_parms);
285 	return ret;
286 }
287 
288 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
289 			      struct wl12xx_vif *wlvif,
290 			      struct ieee80211_channel_switch *ch_switch)
291 {
292 	struct wl12xx_cmd_channel_switch *cmd;
293 	int ret;
294 
295 	wl1271_debug(DEBUG_ACX, "cmd channel switch");
296 
297 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
298 	if (!cmd) {
299 		ret = -ENOMEM;
300 		goto out;
301 	}
302 
303 	cmd->role_id = wlvif->role_id;
304 	cmd->channel = ch_switch->chandef.chan->hw_value;
305 	cmd->switch_time = ch_switch->count;
306 	cmd->stop_tx = ch_switch->block_tx;
307 
308 	/* FIXME: control from mac80211 in the future */
309 	/* Enable TX on the target channel */
310 	cmd->post_switch_tx_disable = 0;
311 
312 	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
313 	if (ret < 0) {
314 		wl1271_error("failed to send channel switch command");
315 		goto out_free;
316 	}
317 
318 out_free:
319 	kfree(cmd);
320 
321 out:
322 	return ret;
323 }
324