ath9k: Fix hanlding of maximum magnitude index
[linux-2.6-block.git] / drivers / net / wireless / ath / ath9k / common-spectral.c
CommitLineData
f65c0825
SM
1/*
2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/relay.h>
18#include "ath9k.h"
19
20static s8 fix_rssi_inv_only(u8 rssi_val)
21{
22 if (rssi_val == 128)
23 rssi_val = 0;
24 return (s8) rssi_val;
25}
26
1111d426 27static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv,
f65c0825
SM
28 struct fft_sample_tlv *fft_sample_tlv)
29{
30 int length;
1111d426 31 if (!spec_priv->rfs_chan_spec_scan)
f65c0825
SM
32 return;
33
34 length = __be16_to_cpu(fft_sample_tlv->length) +
35 sizeof(*fft_sample_tlv);
1111d426 36 relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length);
f65c0825
SM
37}
38
39/* returns 1 if this was a spectral frame, even if not handled. */
67dc74f1 40int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr,
f65c0825
SM
41 struct ath_rx_status *rs, u64 tsf)
42{
1111d426
OR
43 struct ath_hw *ah = spec_priv->ah;
44 struct ath_common *common = ath9k_hw_common(spec_priv->ah);
f65c0825
SM
45 u8 num_bins, *bins, *vdata = (u8 *)hdr;
46 struct fft_sample_ht20 fft_sample_20;
47 struct fft_sample_ht20_40 fft_sample_40;
48 struct fft_sample_tlv *tlv;
49 struct ath_radar_info *radar_info;
50 int len = rs->rs_datalen;
51 int dc_pos;
52 u16 fft_len, length, freq = ah->curchan->chan->center_freq;
53 enum nl80211_channel_type chan_type;
54
55 /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
56 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
57 * yet, but this is supposed to be possible as well.
58 */
59 if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
60 rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
61 rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
62 return 0;
63
64 /* check if spectral scan bit is set. This does not have to be checked
65 * if received through a SPECTRAL phy error, but shouldn't hurt.
66 */
67 radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
68 if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
69 return 0;
70
1111d426 71 chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef);
f65c0825
SM
72 if ((chan_type == NL80211_CHAN_HT40MINUS) ||
73 (chan_type == NL80211_CHAN_HT40PLUS)) {
74 fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
75 num_bins = SPECTRAL_HT20_40_NUM_BINS;
76 bins = (u8 *)fft_sample_40.data;
77 } else {
78 fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
79 num_bins = SPECTRAL_HT20_NUM_BINS;
80 bins = (u8 *)fft_sample_20.data;
81 }
82
83 /* Variation in the data length is possible and will be fixed later */
84 if ((len > fft_len + 2) || (len < fft_len - 1))
85 return 1;
86
87 switch (len - fft_len) {
88 case 0:
89 /* length correct, nothing to do. */
90 memcpy(bins, vdata, num_bins);
91 break;
92 case -1:
93 /* first byte missing, duplicate it. */
94 memcpy(&bins[1], vdata, num_bins - 1);
95 bins[0] = vdata[0];
96 break;
97 case 2:
98 /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
99 memcpy(bins, vdata, 30);
100 bins[30] = vdata[31];
101 memcpy(&bins[31], &vdata[33], num_bins - 31);
102 break;
103 case 1:
104 /* MAC added 2 extra bytes AND first byte is missing. */
105 bins[0] = vdata[0];
106 memcpy(&bins[1], vdata, 30);
107 bins[31] = vdata[31];
108 memcpy(&bins[32], &vdata[33], num_bins - 32);
109 break;
110 default:
111 return 1;
112 }
113
114 /* DC value (value in the middle) is the blind spot of the spectral
115 * sample and invalid, interpolate it.
116 */
117 dc_pos = num_bins / 2;
118 bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
119
120 if ((chan_type == NL80211_CHAN_HT40MINUS) ||
121 (chan_type == NL80211_CHAN_HT40PLUS)) {
122 s8 lower_rssi, upper_rssi;
123 s16 ext_nf;
124 u8 lower_max_index, upper_max_index;
125 u8 lower_bitmap_w, upper_bitmap_w;
126 u16 lower_mag, upper_mag;
127 struct ath9k_hw_cal_data *caldata = ah->caldata;
128 struct ath_ht20_40_mag_info *mag_info;
129
130 if (caldata)
131 ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
132 caldata->nfCalHist[3].privNF);
133 else
134 ext_nf = ATH_DEFAULT_NOISE_FLOOR;
135
136 length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
137 fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
138 fft_sample_40.tlv.length = __cpu_to_be16(length);
139 fft_sample_40.freq = __cpu_to_be16(freq);
140 fft_sample_40.channel_type = chan_type;
141
142 if (chan_type == NL80211_CHAN_HT40PLUS) {
143 lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
144 upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
145
146 fft_sample_40.lower_noise = ah->noise;
147 fft_sample_40.upper_noise = ext_nf;
148 } else {
149 lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
150 upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
151
152 fft_sample_40.lower_noise = ext_nf;
153 fft_sample_40.upper_noise = ah->noise;
154 }
155 fft_sample_40.lower_rssi = lower_rssi;
156 fft_sample_40.upper_rssi = upper_rssi;
157
158 mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
159 lower_mag = spectral_max_magnitude(mag_info->lower_bins);
160 upper_mag = spectral_max_magnitude(mag_info->upper_bins);
161 fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
162 fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
e33f855d
NK
163 lower_max_index = spectral_max_index(mag_info->lower_bins,
164 num_bins);
165 upper_max_index = spectral_max_index(mag_info->upper_bins,
166 num_bins);
f65c0825
SM
167 fft_sample_40.lower_max_index = lower_max_index;
168 fft_sample_40.upper_max_index = upper_max_index;
169 lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
170 upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
171 fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
172 fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
173 fft_sample_40.max_exp = mag_info->max_exp & 0xf;
174
175 fft_sample_40.tsf = __cpu_to_be64(tsf);
176
177 tlv = (struct fft_sample_tlv *)&fft_sample_40;
178 } else {
179 u8 max_index, bitmap_w;
180 u16 magnitude;
181 struct ath_ht20_mag_info *mag_info;
182
183 length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
184 fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
185 fft_sample_20.tlv.length = __cpu_to_be16(length);
186 fft_sample_20.freq = __cpu_to_be16(freq);
187
188 fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
189 fft_sample_20.noise = ah->noise;
190
191 mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
192 magnitude = spectral_max_magnitude(mag_info->all_bins);
193 fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
e33f855d
NK
194 max_index = spectral_max_index(mag_info->all_bins,
195 num_bins);
f65c0825
SM
196 fft_sample_20.max_index = max_index;
197 bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
198 fft_sample_20.bitmap_weight = bitmap_w;
199 fft_sample_20.max_exp = mag_info->max_exp & 0xf;
200
201 fft_sample_20.tsf = __cpu_to_be64(tsf);
202
203 tlv = (struct fft_sample_tlv *)&fft_sample_20;
204 }
205
1111d426 206 ath_debug_send_fft_sample(spec_priv, tlv);
f65c0825
SM
207
208 return 1;
209}
67dc74f1 210EXPORT_SYMBOL(ath_cmn_process_fft);
f65c0825
SM
211
212/*********************/
213/* spectral_scan_ctl */
214/*********************/
215
216static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
217 size_t count, loff_t *ppos)
218{
1111d426 219 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
220 char *mode = "";
221 unsigned int len;
222
1111d426 223 switch (spec_priv->spectral_mode) {
f65c0825
SM
224 case SPECTRAL_DISABLED:
225 mode = "disable";
226 break;
227 case SPECTRAL_BACKGROUND:
228 mode = "background";
229 break;
230 case SPECTRAL_CHANSCAN:
231 mode = "chanscan";
232 break;
233 case SPECTRAL_MANUAL:
234 mode = "manual";
235 break;
236 }
237 len = strlen(mode);
238 return simple_read_from_buffer(user_buf, count, ppos, mode, len);
239}
240
67dc74f1 241void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
f00a422c
OR
242 struct ath_spec_scan_priv *spec_priv)
243{
244 struct ath_hw *ah = spec_priv->ah;
245 u32 rxfilter;
246
247 if (config_enabled(CONFIG_ATH9K_TX99))
248 return;
249
250 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
251 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
252 return;
253 }
254
255 ath_ps_ops(common)->wakeup(common);
256 rxfilter = ath9k_hw_getrxfilter(ah);
257 ath9k_hw_setrxfilter(ah, rxfilter |
258 ATH9K_RX_FILTER_PHYRADAR |
259 ATH9K_RX_FILTER_PHYERR);
260
261 /* TODO: usually this should not be neccesary, but for some reason
262 * (or in some mode?) the trigger must be called after the
263 * configuration, otherwise the register will have its values reset
264 * (on my ar9220 to value 0x01002310)
265 */
67dc74f1 266 ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode);
f00a422c
OR
267 ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
268 ath_ps_ops(common)->restore(common);
269}
67dc74f1 270EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger);
f00a422c 271
67dc74f1 272int ath9k_cmn_spectral_scan_config(struct ath_common *common,
f00a422c
OR
273 struct ath_spec_scan_priv *spec_priv,
274 enum spectral_mode spectral_mode)
275{
276 struct ath_hw *ah = spec_priv->ah;
277
278 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
279 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
280 return -1;
281 }
282
283 switch (spectral_mode) {
284 case SPECTRAL_DISABLED:
285 spec_priv->spec_config.enabled = 0;
286 break;
287 case SPECTRAL_BACKGROUND:
288 /* send endless samples.
289 * TODO: is this really useful for "background"?
290 */
291 spec_priv->spec_config.endless = 1;
292 spec_priv->spec_config.enabled = 1;
293 break;
294 case SPECTRAL_CHANSCAN:
295 case SPECTRAL_MANUAL:
296 spec_priv->spec_config.endless = 0;
297 spec_priv->spec_config.enabled = 1;
298 break;
299 default:
300 return -1;
301 }
302
303 ath_ps_ops(common)->wakeup(common);
304 ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config);
305 ath_ps_ops(common)->restore(common);
306
307 spec_priv->spectral_mode = spectral_mode;
308
309 return 0;
310}
67dc74f1 311EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config);
f00a422c 312
f65c0825
SM
313static ssize_t write_file_spec_scan_ctl(struct file *file,
314 const char __user *user_buf,
315 size_t count, loff_t *ppos)
316{
1111d426
OR
317 struct ath_spec_scan_priv *spec_priv = file->private_data;
318 struct ath_common *common = ath9k_hw_common(spec_priv->ah);
f65c0825
SM
319 char buf[32];
320 ssize_t len;
321
322 if (config_enabled(CONFIG_ATH9K_TX99))
323 return -EOPNOTSUPP;
324
325 len = min(count, sizeof(buf) - 1);
326 if (copy_from_user(buf, user_buf, len))
327 return -EFAULT;
328
329 buf[len] = '\0';
330
331 if (strncmp("trigger", buf, 7) == 0) {
67dc74f1 332 ath9k_cmn_spectral_scan_trigger(common, spec_priv);
ded3fb4c 333 } else if (strncmp("background", buf, 10) == 0) {
67dc74f1 334 ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND);
f65c0825
SM
335 ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
336 } else if (strncmp("chanscan", buf, 8) == 0) {
67dc74f1 337 ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN);
f65c0825
SM
338 ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
339 } else if (strncmp("manual", buf, 6) == 0) {
67dc74f1 340 ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL);
f65c0825
SM
341 ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
342 } else if (strncmp("disable", buf, 7) == 0) {
67dc74f1 343 ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED);
f65c0825
SM
344 ath_dbg(common, CONFIG, "spectral scan: disabled\n");
345 } else {
346 return -EINVAL;
347 }
348
349 return count;
350}
351
352static const struct file_operations fops_spec_scan_ctl = {
353 .read = read_file_spec_scan_ctl,
354 .write = write_file_spec_scan_ctl,
355 .open = simple_open,
356 .owner = THIS_MODULE,
357 .llseek = default_llseek,
358};
359
360/*************************/
361/* spectral_short_repeat */
362/*************************/
363
364static ssize_t read_file_spectral_short_repeat(struct file *file,
365 char __user *user_buf,
366 size_t count, loff_t *ppos)
367{
1111d426 368 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
369 char buf[32];
370 unsigned int len;
371
1111d426 372 len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat);
f65c0825
SM
373 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
374}
375
376static ssize_t write_file_spectral_short_repeat(struct file *file,
377 const char __user *user_buf,
378 size_t count, loff_t *ppos)
379{
1111d426 380 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
381 unsigned long val;
382 char buf[32];
383 ssize_t len;
384
385 len = min(count, sizeof(buf) - 1);
386 if (copy_from_user(buf, user_buf, len))
387 return -EFAULT;
388
389 buf[len] = '\0';
390 if (kstrtoul(buf, 0, &val))
391 return -EINVAL;
392
3f557202 393 if (val > 1)
f65c0825
SM
394 return -EINVAL;
395
1111d426 396 spec_priv->spec_config.short_repeat = val;
f65c0825
SM
397 return count;
398}
399
400static const struct file_operations fops_spectral_short_repeat = {
401 .read = read_file_spectral_short_repeat,
402 .write = write_file_spectral_short_repeat,
403 .open = simple_open,
404 .owner = THIS_MODULE,
405 .llseek = default_llseek,
406};
407
408/******************/
409/* spectral_count */
410/******************/
411
412static ssize_t read_file_spectral_count(struct file *file,
413 char __user *user_buf,
414 size_t count, loff_t *ppos)
415{
1111d426 416 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
417 char buf[32];
418 unsigned int len;
419
1111d426 420 len = sprintf(buf, "%d\n", spec_priv->spec_config.count);
f65c0825
SM
421 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
422}
423
424static ssize_t write_file_spectral_count(struct file *file,
425 const char __user *user_buf,
426 size_t count, loff_t *ppos)
427{
1111d426 428 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
429 unsigned long val;
430 char buf[32];
431 ssize_t len;
432
433 len = min(count, sizeof(buf) - 1);
434 if (copy_from_user(buf, user_buf, len))
435 return -EFAULT;
436
437 buf[len] = '\0';
438 if (kstrtoul(buf, 0, &val))
439 return -EINVAL;
440
3f557202 441 if (val > 255)
f65c0825
SM
442 return -EINVAL;
443
1111d426 444 spec_priv->spec_config.count = val;
f65c0825
SM
445 return count;
446}
447
448static const struct file_operations fops_spectral_count = {
449 .read = read_file_spectral_count,
450 .write = write_file_spectral_count,
451 .open = simple_open,
452 .owner = THIS_MODULE,
453 .llseek = default_llseek,
454};
455
456/*******************/
457/* spectral_period */
458/*******************/
459
460static ssize_t read_file_spectral_period(struct file *file,
461 char __user *user_buf,
462 size_t count, loff_t *ppos)
463{
1111d426 464 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
465 char buf[32];
466 unsigned int len;
467
1111d426 468 len = sprintf(buf, "%d\n", spec_priv->spec_config.period);
f65c0825
SM
469 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
470}
471
472static ssize_t write_file_spectral_period(struct file *file,
473 const char __user *user_buf,
474 size_t count, loff_t *ppos)
475{
1111d426 476 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
477 unsigned long val;
478 char buf[32];
479 ssize_t len;
480
481 len = min(count, sizeof(buf) - 1);
482 if (copy_from_user(buf, user_buf, len))
483 return -EFAULT;
484
485 buf[len] = '\0';
486 if (kstrtoul(buf, 0, &val))
487 return -EINVAL;
488
3f557202 489 if (val > 255)
f65c0825
SM
490 return -EINVAL;
491
1111d426 492 spec_priv->spec_config.period = val;
f65c0825
SM
493 return count;
494}
495
496static const struct file_operations fops_spectral_period = {
497 .read = read_file_spectral_period,
498 .write = write_file_spectral_period,
499 .open = simple_open,
500 .owner = THIS_MODULE,
501 .llseek = default_llseek,
502};
503
504/***********************/
505/* spectral_fft_period */
506/***********************/
507
508static ssize_t read_file_spectral_fft_period(struct file *file,
509 char __user *user_buf,
510 size_t count, loff_t *ppos)
511{
1111d426 512 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
513 char buf[32];
514 unsigned int len;
515
1111d426 516 len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period);
f65c0825
SM
517 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
518}
519
520static ssize_t write_file_spectral_fft_period(struct file *file,
521 const char __user *user_buf,
522 size_t count, loff_t *ppos)
523{
1111d426 524 struct ath_spec_scan_priv *spec_priv = file->private_data;
f65c0825
SM
525 unsigned long val;
526 char buf[32];
527 ssize_t len;
528
529 len = min(count, sizeof(buf) - 1);
530 if (copy_from_user(buf, user_buf, len))
531 return -EFAULT;
532
533 buf[len] = '\0';
534 if (kstrtoul(buf, 0, &val))
535 return -EINVAL;
536
3f557202 537 if (val > 15)
f65c0825
SM
538 return -EINVAL;
539
1111d426 540 spec_priv->spec_config.fft_period = val;
f65c0825
SM
541 return count;
542}
543
544static const struct file_operations fops_spectral_fft_period = {
545 .read = read_file_spectral_fft_period,
546 .write = write_file_spectral_fft_period,
547 .open = simple_open,
548 .owner = THIS_MODULE,
549 .llseek = default_llseek,
550};
551
552/*******************/
553/* Relay interface */
554/*******************/
555
556static struct dentry *create_buf_file_handler(const char *filename,
557 struct dentry *parent,
558 umode_t mode,
559 struct rchan_buf *buf,
560 int *is_global)
561{
562 struct dentry *buf_file;
563
564 buf_file = debugfs_create_file(filename, mode, parent, buf,
565 &relay_file_operations);
566 *is_global = 1;
567 return buf_file;
568}
569
570static int remove_buf_file_handler(struct dentry *dentry)
571{
572 debugfs_remove(dentry);
573
574 return 0;
575}
576
f84d1b49 577static struct rchan_callbacks rfs_spec_scan_cb = {
f65c0825
SM
578 .create_buf_file = create_buf_file_handler,
579 .remove_buf_file = remove_buf_file_handler,
580};
581
582/*********************/
583/* Debug Init/Deinit */
584/*********************/
585
67dc74f1 586void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
f65c0825 587{
c0420ea0 588 if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
1111d426
OR
589 relay_close(spec_priv->rfs_chan_spec_scan);
590 spec_priv->rfs_chan_spec_scan = NULL;
f65c0825
SM
591 }
592}
67dc74f1 593EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug);
f65c0825 594
67dc74f1
OR
595void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
596 struct dentry *debugfs_phy)
f65c0825 597{
1111d426 598 spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan",
c10b75af 599 debugfs_phy,
f65c0825
SM
600 1024, 256, &rfs_spec_scan_cb,
601 NULL);
602 debugfs_create_file("spectral_scan_ctl",
603 S_IRUSR | S_IWUSR,
1111d426 604 debugfs_phy, spec_priv,
f65c0825
SM
605 &fops_spec_scan_ctl);
606 debugfs_create_file("spectral_short_repeat",
607 S_IRUSR | S_IWUSR,
1111d426 608 debugfs_phy, spec_priv,
f65c0825
SM
609 &fops_spectral_short_repeat);
610 debugfs_create_file("spectral_count",
611 S_IRUSR | S_IWUSR,
1111d426 612 debugfs_phy, spec_priv,
f65c0825
SM
613 &fops_spectral_count);
614 debugfs_create_file("spectral_period",
615 S_IRUSR | S_IWUSR,
1111d426 616 debugfs_phy, spec_priv,
f65c0825
SM
617 &fops_spectral_period);
618 debugfs_create_file("spectral_fft_period",
619 S_IRUSR | S_IWUSR,
1111d426 620 debugfs_phy, spec_priv,
f65c0825
SM
621 &fops_spectral_fft_period);
622}
67dc74f1 623EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug);