|
@@ -1120,6 +1120,124 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
|
|
|
#undef SHIFT
|
|
|
}
|
|
|
|
|
|
+static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 3; i++)
|
|
|
+ if (x <= x_array[i + 1])
|
|
|
+ break;
|
|
|
+
|
|
|
+ return ar9170_interpolate_u8(x,
|
|
|
+ x_array[i],
|
|
|
+ y_array[i],
|
|
|
+ x_array[i + 1],
|
|
|
+ y_array[i + 1]);
|
|
|
+}
|
|
|
+
|
|
|
+static int ar9170_set_freq_cal_data(struct ar9170 *ar,
|
|
|
+ struct ieee80211_channel *channel)
|
|
|
+{
|
|
|
+ u8 *cal_freq_pier;
|
|
|
+ u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
|
|
|
+ u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
|
|
|
+ int chain, idx, i;
|
|
|
+ u8 f;
|
|
|
+
|
|
|
+ switch (channel->band) {
|
|
|
+ case IEEE80211_BAND_2GHZ:
|
|
|
+ f = channel->center_freq - 2300;
|
|
|
+ cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
|
|
|
+ i = AR5416_NUM_2G_CAL_PIERS - 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IEEE80211_BAND_5GHZ:
|
|
|
+ f = (channel->center_freq - 4800) / 5;
|
|
|
+ cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
|
|
|
+ i = AR5416_NUM_5G_CAL_PIERS - 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (; i >= 0; i--) {
|
|
|
+ if (cal_freq_pier[i] != 0xff)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (i < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ idx = ar9170_find_freq_idx(i, cal_freq_pier, f);
|
|
|
+
|
|
|
+ ar9170_regwrite_begin(ar);
|
|
|
+
|
|
|
+ for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
|
|
|
+ for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
|
|
|
+ struct ar9170_calibration_data_per_freq *cal_pier_data;
|
|
|
+ int j;
|
|
|
+
|
|
|
+ switch (channel->band) {
|
|
|
+ case IEEE80211_BAND_2GHZ:
|
|
|
+ cal_pier_data = &ar->eeprom.
|
|
|
+ cal_pier_data_2G[chain][idx];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IEEE80211_BAND_5GHZ:
|
|
|
+ cal_pier_data = &ar->eeprom.
|
|
|
+ cal_pier_data_5G[chain][idx];
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (j = 0; j < 2; j++) {
|
|
|
+ vpds[j][i] = ar9170_interpolate_u8(f,
|
|
|
+ cal_freq_pier[idx],
|
|
|
+ cal_pier_data->vpd_pdg[j][i],
|
|
|
+ cal_freq_pier[idx + 1],
|
|
|
+ cal_pier_data[1].vpd_pdg[j][i]);
|
|
|
+
|
|
|
+ pwrs[j][i] = ar9170_interpolate_u8(f,
|
|
|
+ cal_freq_pier[idx],
|
|
|
+ cal_pier_data->pwr_pdg[j][i],
|
|
|
+ cal_freq_pier[idx + 1],
|
|
|
+ cal_pier_data[1].pwr_pdg[j][i]) / 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < 76; i++) {
|
|
|
+ u32 phy_data;
|
|
|
+ u8 tmp;
|
|
|
+
|
|
|
+ if (i < 25) {
|
|
|
+ tmp = ar9170_interpolate_val(i, &pwrs[0][0],
|
|
|
+ &vpds[0][0]);
|
|
|
+ } else {
|
|
|
+ tmp = ar9170_interpolate_val(i - 12,
|
|
|
+ &pwrs[1][0],
|
|
|
+ &vpds[1][0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ phy_data |= tmp << ((i & 3) << 3);
|
|
|
+ if ((i & 3) == 3) {
|
|
|
+ ar9170_regwrite(0x1c6280 + chain * 0x1000 +
|
|
|
+ (i & ~3), phy_data);
|
|
|
+ phy_data = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 19; i < 32; i++)
|
|
|
+ ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
|
|
|
+ 0x0);
|
|
|
+ }
|
|
|
+
|
|
|
+ ar9170_regwrite_finish();
|
|
|
+ return ar9170_regwrite_result();
|
|
|
+}
|
|
|
+
|
|
|
static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
|
|
|
{
|
|
|
struct ar9170_calibration_target_power_legacy *ctpl;
|
|
@@ -1340,6 +1458,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ err = ar9170_set_freq_cal_data(ar, channel);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
err = ar9170_set_power_cal(ar, channel->center_freq, bw);
|
|
|
if (err)
|
|
|
return err;
|