Commit | Line | Data |
---|---|---|
f6532111 MW |
1 | /* |
2 | * Radio tuning for Maxim max2820 on RTL8180 | |
3 | * | |
4 | * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> | |
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 | ||
21 | #include <linux/init.h> | |
22 | #include <linux/pci.h> | |
23 | #include <linux/delay.h> | |
24 | #include <net/mac80211.h> | |
25 | ||
26 | #include "rtl8180.h" | |
27 | #include "rtl8180_max2820.h" | |
28 | ||
29 | static const u32 max2820_chan[] = { | |
30 | 12, /* CH 1 */ | |
31 | 17, | |
32 | 22, | |
33 | 27, | |
34 | 32, | |
35 | 37, | |
36 | 42, | |
37 | 47, | |
38 | 52, | |
39 | 57, | |
40 | 62, | |
41 | 67, | |
42 | 72, | |
43 | 84, /* CH 14 */ | |
44 | }; | |
45 | ||
46 | static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) | |
47 | { | |
48 | struct rtl8180_priv *priv = dev->priv; | |
49 | u32 phy_config; | |
50 | ||
51 | phy_config = 0x90 + (data & 0xf); | |
52 | phy_config <<= 16; | |
53 | phy_config += addr; | |
54 | phy_config <<= 8; | |
55 | phy_config += (data >> 4) & 0xff; | |
56 | ||
57 | rtl818x_iowrite32(priv, | |
58 | (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); | |
59 | ||
60 | msleep(1); | |
61 | } | |
62 | ||
63 | static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) | |
64 | { | |
65 | struct rtl8180_priv *priv = dev->priv; | |
66 | u8 ant; | |
67 | ||
68 | ant = MAXIM_ANTENNA; | |
69 | if (priv->rfparam & RF_PARAM_ANTBDEFAULT) | |
70 | ant |= BB_ANTENNA_B; | |
71 | if (chan == 14) | |
72 | ant |= BB_ANTATTEN_CHAN14; | |
73 | ||
74 | rtl8180_write_phy(dev, 0x10, ant); | |
75 | } | |
76 | ||
77 | static void max2820_rf_set_channel(struct ieee80211_hw *dev, | |
78 | struct ieee80211_conf *conf) | |
79 | { | |
80 | struct rtl8180_priv *priv = dev->priv; | |
6f6c218f JL |
81 | int channel = conf ? |
82 | ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; | |
8318d78a JB |
83 | unsigned int chan_idx = channel - 1; |
84 | u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; | |
f6532111 MW |
85 | u32 chan = max2820_chan[chan_idx]; |
86 | ||
87 | /* While philips SA2400 drive the PA bias from | |
88 | * sa2400, for MAXIM we do this directly from BB */ | |
89 | rtl8180_write_phy(dev, 3, txpw); | |
90 | ||
0a0ab41e | 91 | max2820_write_phy_antenna(dev, channel); |
f6532111 MW |
92 | write_max2820(dev, 3, chan); |
93 | } | |
94 | ||
95 | static void max2820_rf_stop(struct ieee80211_hw *dev) | |
96 | { | |
97 | rtl8180_write_phy(dev, 3, 0x8); | |
98 | write_max2820(dev, 1, 0); | |
99 | } | |
100 | ||
101 | ||
102 | static void max2820_rf_init(struct ieee80211_hw *dev) | |
103 | { | |
104 | struct rtl8180_priv *priv = dev->priv; | |
105 | ||
106 | /* MAXIM from netbsd driver */ | |
107 | write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ | |
108 | write_max2820(dev, 1, 0x01e); /* enable register */ | |
109 | write_max2820(dev, 2, 0x001); /* synt register */ | |
110 | ||
111 | max2820_rf_set_channel(dev, NULL); | |
112 | ||
113 | write_max2820(dev, 4, 0x313); /* rx register */ | |
114 | ||
115 | /* PA is driven directly by the BB, we keep the MAXIM bias | |
116 | * at the highest value in case that setting it to lower | |
117 | * values may introduce some further attenuation somewhere.. | |
118 | */ | |
119 | write_max2820(dev, 5, 0x00f); | |
120 | ||
121 | /* baseband configuration */ | |
122 | rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ | |
123 | rtl8180_write_phy(dev, 3, 0x08); /* txagc */ | |
124 | rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ | |
125 | rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ | |
126 | rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ | |
127 | rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ | |
128 | ||
129 | max2820_write_phy_antenna(dev, 1); | |
130 | ||
131 | rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ | |
132 | ||
133 | if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & | |
134 | RTL818X_CONFIG2_ANTENNA_DIV) | |
135 | rtl8180_write_phy(dev, 0x12, 0xc7); | |
136 | else | |
137 | rtl8180_write_phy(dev, 0x12, 0x47); | |
138 | ||
139 | rtl8180_write_phy(dev, 0x13, 0x9b); | |
140 | ||
141 | rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ | |
142 | rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ | |
143 | ||
144 | max2820_rf_set_channel(dev, NULL); | |
145 | } | |
146 | ||
147 | const struct rtl818x_rf_ops max2820_rf_ops = { | |
148 | .name = "Maxim", | |
149 | .init = max2820_rf_init, | |
150 | .stop = max2820_rf_stop, | |
151 | .set_chan = max2820_rf_set_channel | |
152 | }; |