Commit | Line | Data |
---|---|---|
f6532111 MW |
1 | /* |
2 | * Radio tuning for Maxim max2820 on RTL8180 | |
3 | * | |
93ba2a85 | 4 | * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> |
f6532111 MW |
5 | * |
6 | * Code from the BSD driver and the rtl8181 project have been | |
7 | * very useful to understand certain things | |
8 | * | |
9 | * I want to thanks the Authors of such projects and the Ndiswrapper | |
10 | * project Authors. | |
11 | * | |
12 | * A special Big Thanks also is for all people who donated me cards, | |
13 | * making possible the creation of the original rtl8180 driver | |
14 | * from which this code is derived! | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License version 2 as | |
18 | * published by the Free Software Foundation. | |
19 | */ | |
20 | ||
f6532111 MW |
21 | #include <linux/pci.h> |
22 | #include <linux/delay.h> | |
23 | #include <net/mac80211.h> | |
24 | ||
25 | #include "rtl8180.h" | |
3cfeb0c3 | 26 | #include "max2820.h" |
f6532111 MW |
27 | |
28 | static const u32 max2820_chan[] = { | |
29 | 12, /* CH 1 */ | |
30 | 17, | |
31 | 22, | |
32 | 27, | |
33 | 32, | |
34 | 37, | |
35 | 42, | |
36 | 47, | |
37 | 52, | |
38 | 57, | |
39 | 62, | |
40 | 67, | |
41 | 72, | |
42 | 84, /* CH 14 */ | |
43 | }; | |
44 | ||
45 | static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) | |
46 | { | |
47 | struct rtl8180_priv *priv = dev->priv; | |
48 | u32 phy_config; | |
49 | ||
50 | phy_config = 0x90 + (data & 0xf); | |
51 | phy_config <<= 16; | |
52 | phy_config += addr; | |
53 | phy_config <<= 8; | |
54 | phy_config += (data >> 4) & 0xff; | |
55 | ||
56 | rtl818x_iowrite32(priv, | |
57 | (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); | |
58 | ||
59 | msleep(1); | |
60 | } | |
61 | ||
62 | static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) | |
63 | { | |
64 | struct rtl8180_priv *priv = dev->priv; | |
65 | u8 ant; | |
66 | ||
67 | ant = MAXIM_ANTENNA; | |
68 | if (priv->rfparam & RF_PARAM_ANTBDEFAULT) | |
69 | ant |= BB_ANTENNA_B; | |
70 | if (chan == 14) | |
71 | ant |= BB_ANTATTEN_CHAN14; | |
72 | ||
73 | rtl8180_write_phy(dev, 0x10, ant); | |
74 | } | |
75 | ||
8b73fb8e JL |
76 | static u8 max2820_rf_calc_rssi(u8 agc, u8 sq) |
77 | { | |
78 | bool odd; | |
79 | ||
80 | odd = !!(agc & 1); | |
81 | ||
82 | agc >>= 1; | |
83 | if (odd) | |
84 | agc += 76; | |
85 | else | |
86 | agc += 66; | |
87 | ||
88 | /* TODO: change addends above to avoid mult / div below */ | |
89 | return 65 * agc / 100; | |
90 | } | |
91 | ||
f6532111 MW |
92 | static void max2820_rf_set_channel(struct ieee80211_hw *dev, |
93 | struct ieee80211_conf *conf) | |
94 | { | |
95 | struct rtl8180_priv *priv = dev->priv; | |
6f6c218f | 96 | int channel = conf ? |
675a0b04 | 97 | ieee80211_frequency_to_channel(conf->chandef.chan->center_freq) : 1; |
8318d78a JB |
98 | unsigned int chan_idx = channel - 1; |
99 | u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; | |
f6532111 MW |
100 | u32 chan = max2820_chan[chan_idx]; |
101 | ||
102 | /* While philips SA2400 drive the PA bias from | |
103 | * sa2400, for MAXIM we do this directly from BB */ | |
104 | rtl8180_write_phy(dev, 3, txpw); | |
105 | ||
0a0ab41e | 106 | max2820_write_phy_antenna(dev, channel); |
f6532111 MW |
107 | write_max2820(dev, 3, chan); |
108 | } | |
109 | ||
110 | static void max2820_rf_stop(struct ieee80211_hw *dev) | |
111 | { | |
112 | rtl8180_write_phy(dev, 3, 0x8); | |
113 | write_max2820(dev, 1, 0); | |
114 | } | |
115 | ||
116 | ||
117 | static void max2820_rf_init(struct ieee80211_hw *dev) | |
118 | { | |
119 | struct rtl8180_priv *priv = dev->priv; | |
120 | ||
121 | /* MAXIM from netbsd driver */ | |
122 | write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ | |
123 | write_max2820(dev, 1, 0x01e); /* enable register */ | |
124 | write_max2820(dev, 2, 0x001); /* synt register */ | |
125 | ||
126 | max2820_rf_set_channel(dev, NULL); | |
127 | ||
128 | write_max2820(dev, 4, 0x313); /* rx register */ | |
129 | ||
130 | /* PA is driven directly by the BB, we keep the MAXIM bias | |
131 | * at the highest value in case that setting it to lower | |
132 | * values may introduce some further attenuation somewhere.. | |
133 | */ | |
134 | write_max2820(dev, 5, 0x00f); | |
135 | ||
136 | /* baseband configuration */ | |
137 | rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ | |
138 | rtl8180_write_phy(dev, 3, 0x08); /* txagc */ | |
139 | rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ | |
140 | rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ | |
141 | rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ | |
142 | rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ | |
143 | ||
144 | max2820_write_phy_antenna(dev, 1); | |
145 | ||
146 | rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ | |
147 | ||
148 | if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & | |
149 | RTL818X_CONFIG2_ANTENNA_DIV) | |
150 | rtl8180_write_phy(dev, 0x12, 0xc7); | |
151 | else | |
152 | rtl8180_write_phy(dev, 0x12, 0x47); | |
153 | ||
154 | rtl8180_write_phy(dev, 0x13, 0x9b); | |
155 | ||
156 | rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ | |
157 | rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ | |
158 | ||
159 | max2820_rf_set_channel(dev, NULL); | |
160 | } | |
161 | ||
162 | const struct rtl818x_rf_ops max2820_rf_ops = { | |
163 | .name = "Maxim", | |
164 | .init = max2820_rf_init, | |
165 | .stop = max2820_rf_stop, | |
8b73fb8e JL |
166 | .set_chan = max2820_rf_set_channel, |
167 | .calc_rssi = max2820_rf_calc_rssi, | |
f6532111 | 168 | }; |