Skip to content

Commit c869f77

Browse files
kuba-mooKalle Valo
authored andcommitted
add mt7601u driver
Add support for the simplest of MediaTek Wi-Fi devices - MT7601U. It is a single stream bgn chip with no bells or whistles. This driver is partially based on Felix's mt76 but IMHO it doesn't make sense to merge the two right now because MT7601U is a design somewhere between old Ralink devices and new Mediatek chips. There wouldn't be all that much code sharing with the devices mt76 supports. Situation may obviously change when someone decides to extend m76 with support for the more recent USB dongles. The driver supports only station mode. I'm hoping to add AP support when time allows. This driver sat on GitHub for quite a while and got some testing there: http://github.com/kuba-moo/mt7601u Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Kalle Valo <[email protected]>
1 parent 00e27ee commit c869f77

31 files changed

+7950
-0
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6365,6 +6365,12 @@ F: include/uapi/linux/meye.h
63656365
F: include/uapi/linux/ivtv*
63666366
F: include/uapi/linux/uvcvideo.h
63676367

6368+
MEDIATEK MT7601U WIRELESS LAN DRIVER
6369+
M: Jakub Kicinski <[email protected]>
6370+
6371+
S: Maintained
6372+
F: drivers/net/wireless/mediatek/mt7601u/
6373+
63686374
MEGARAID SCSI/SAS DRIVERS
63696375
M: Kashyap Desai <[email protected]>
63706376
M: Sumit Saxena <[email protected]>

drivers/net/wireless/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ source "drivers/net/wireless/libertas/Kconfig"
277277
source "drivers/net/wireless/orinoco/Kconfig"
278278
source "drivers/net/wireless/p54/Kconfig"
279279
source "drivers/net/wireless/rt2x00/Kconfig"
280+
source "drivers/net/wireless/mediatek/Kconfig"
280281
source "drivers/net/wireless/rtlwifi/Kconfig"
281282
source "drivers/net/wireless/ti/Kconfig"
282283
source "drivers/net/wireless/zd1211rw/Kconfig"

drivers/net/wireless/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi/
4545
obj-$(CONFIG_IWLEGACY) += iwlegacy/
4646
obj-$(CONFIG_RT2X00) += rt2x00/
4747

48+
obj-$(CONFIG_WL_MEDIATEK) += mediatek/
49+
4850
obj-$(CONFIG_P54_COMMON) += p54/
4951

5052
obj-$(CONFIG_ATH_CARDS) += ath/

drivers/net/wireless/mediatek/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
menuconfig WL_MEDIATEK
2+
bool "Mediatek Wireless LAN support"
3+
---help---
4+
Enable community drivers for MediaTek WiFi devices.
5+
Those drivers make use of the Linux mac80211 stack.
6+
7+
8+
if WL_MEDIATEK
9+
source "drivers/net/wireless/mediatek/mt7601u/Kconfig"
10+
endif # WL_MEDIATEK
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-$(CONFIG_MT7601U) += mt7601u/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
config MT7601U
2+
tristate "MediaTek MT7601U (USB) support"
3+
depends on MAC80211
4+
depends on USB
5+
---help---
6+
This adds support for MT7601U-based wireless USB dongles.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ccflags-y += -D__CHECK_ENDIAN__
2+
3+
obj-$(CONFIG_MT7601U) += mt7601u.o
4+
5+
mt7601u-objs = \
6+
usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \
7+
mac.o util.o debugfs.o tx.o
8+
9+
CFLAGS_trace.o := -I$(src)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (C) 2014 Felix Fietkau <[email protected]>
3+
* Copyright (C) 2015 Jakub Kicinski <[email protected]>
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License version 2
7+
* as published by the Free Software Foundation
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*/
14+
15+
#include "mt7601u.h"
16+
17+
int mt7601u_wait_asic_ready(struct mt7601u_dev *dev)
18+
{
19+
int i = 100;
20+
u32 val;
21+
22+
do {
23+
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
24+
return -EIO;
25+
26+
val = mt7601u_rr(dev, MT_MAC_CSR0);
27+
if (val && ~val)
28+
return 0;
29+
30+
udelay(10);
31+
} while (i--);
32+
33+
return -EIO;
34+
}
35+
36+
bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
37+
int timeout)
38+
{
39+
u32 cur;
40+
41+
timeout /= 10;
42+
do {
43+
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
44+
return false;
45+
46+
cur = mt7601u_rr(dev, offset) & mask;
47+
if (cur == val)
48+
return true;
49+
50+
udelay(10);
51+
} while (timeout-- > 0);
52+
53+
dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
54+
55+
return false;
56+
}
57+
58+
bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
59+
int timeout)
60+
{
61+
u32 cur;
62+
63+
timeout /= 10;
64+
do {
65+
if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
66+
return false;
67+
68+
cur = mt7601u_rr(dev, offset) & mask;
69+
if (cur == val)
70+
return true;
71+
72+
msleep(10);
73+
} while (timeout-- > 0);
74+
75+
dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
76+
77+
return false;
78+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright (C) 2014 Felix Fietkau <[email protected]>
3+
* Copyright (C) 2015 Jakub Kicinski <[email protected]>
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License version 2
7+
* as published by the Free Software Foundation
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*/
14+
15+
#include <linux/debugfs.h>
16+
17+
#include "mt7601u.h"
18+
#include "eeprom.h"
19+
20+
static int
21+
mt76_reg_set(void *data, u64 val)
22+
{
23+
struct mt7601u_dev *dev = data;
24+
25+
mt76_wr(dev, dev->debugfs_reg, val);
26+
return 0;
27+
}
28+
29+
static int
30+
mt76_reg_get(void *data, u64 *val)
31+
{
32+
struct mt7601u_dev *dev = data;
33+
34+
*val = mt76_rr(dev, dev->debugfs_reg);
35+
return 0;
36+
}
37+
38+
DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
39+
40+
static int
41+
mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
42+
{
43+
struct mt7601u_dev *dev = file->private;
44+
int i, j;
45+
46+
#define stat_printf(grp, off, name) \
47+
seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off])
48+
49+
stat_printf(rx_stat, 0, rx_crc_err);
50+
stat_printf(rx_stat, 1, rx_phy_err);
51+
stat_printf(rx_stat, 2, rx_false_cca);
52+
stat_printf(rx_stat, 3, rx_plcp_err);
53+
stat_printf(rx_stat, 4, rx_fifo_overflow);
54+
stat_printf(rx_stat, 5, rx_duplicate);
55+
56+
stat_printf(tx_stat, 0, tx_fail_cnt);
57+
stat_printf(tx_stat, 1, tx_bcn_cnt);
58+
stat_printf(tx_stat, 2, tx_success);
59+
stat_printf(tx_stat, 3, tx_retransmit);
60+
stat_printf(tx_stat, 4, tx_zero_len);
61+
stat_printf(tx_stat, 5, tx_underflow);
62+
63+
stat_printf(aggr_stat, 0, non_aggr_tx);
64+
stat_printf(aggr_stat, 1, aggr_tx);
65+
66+
stat_printf(zero_len_del, 0, tx_zero_len_del);
67+
stat_printf(zero_len_del, 1, rx_zero_len_del);
68+
#undef stat_printf
69+
70+
seq_puts(file, "Aggregations stats:\n");
71+
for (i = 0; i < 4; i++) {
72+
for (j = 0; j < 8; j++)
73+
seq_printf(file, "%08llx ",
74+
dev->stats.aggr_n[i * 8 + j]);
75+
seq_putc(file, '\n');
76+
}
77+
78+
seq_printf(file, "recent average AMPDU len: %d\n",
79+
atomic_read(&dev->avg_ampdu_len));
80+
81+
return 0;
82+
}
83+
84+
static int
85+
mt7601u_ampdu_stat_open(struct inode *inode, struct file *f)
86+
{
87+
return single_open(f, mt7601u_ampdu_stat_read, inode->i_private);
88+
}
89+
90+
static const struct file_operations fops_ampdu_stat = {
91+
.open = mt7601u_ampdu_stat_open,
92+
.read = seq_read,
93+
.llseek = seq_lseek,
94+
.release = single_release,
95+
};
96+
97+
static int
98+
mt7601u_eeprom_param_read(struct seq_file *file, void *data)
99+
{
100+
struct mt7601u_dev *dev = file->private;
101+
struct mt7601u_rate_power *rp = &dev->ee->power_rate_table;
102+
struct tssi_data *td = &dev->ee->tssi_data;
103+
int i;
104+
105+
seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
106+
seq_printf(file, "RSSI offset: %hhx %hhx\n",
107+
dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]);
108+
seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp);
109+
seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain);
110+
seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start,
111+
dev->ee->reg.start + dev->ee->reg.num - 1);
112+
113+
seq_puts(file, "Per rate power:\n");
114+
for (i = 0; i < 2; i++)
115+
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
116+
rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40);
117+
for (i = 0; i < 4; i++)
118+
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
119+
rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40);
120+
for (i = 0; i < 4; i++)
121+
seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
122+
rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40);
123+
124+
seq_puts(file, "Per channel power:\n");
125+
for (i = 0; i < 7; i++)
126+
seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n",
127+
i * 2 + 1, dev->ee->chan_pwr[i * 2],
128+
i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]);
129+
130+
if (!dev->ee->tssi_enabled)
131+
return 0;
132+
133+
seq_puts(file, "TSSI:\n");
134+
seq_printf(file, "\t slope:%02hhx\n", td->slope);
135+
seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n",
136+
td->offset[0], td->offset[1], td->offset[2]);
137+
seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset);
138+
139+
return 0;
140+
}
141+
142+
static int
143+
mt7601u_eeprom_param_open(struct inode *inode, struct file *f)
144+
{
145+
return single_open(f, mt7601u_eeprom_param_read, inode->i_private);
146+
}
147+
148+
static const struct file_operations fops_eeprom_param = {
149+
.open = mt7601u_eeprom_param_open,
150+
.read = seq_read,
151+
.llseek = seq_lseek,
152+
.release = single_release,
153+
};
154+
155+
void mt7601u_init_debugfs(struct mt7601u_dev *dev)
156+
{
157+
struct dentry *dir;
158+
159+
dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir);
160+
if (!dir)
161+
return;
162+
163+
debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp);
164+
debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode);
165+
166+
debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
167+
debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
168+
&fops_regval);
169+
debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
170+
debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
171+
&fops_eeprom_param);
172+
}

0 commit comments

Comments
 (0)