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