+static void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower);
+
+/* Adjust the transmission power output (G-PHY) */
+void bcm43xx_set_txpower_g(struct bcm43xx_wldev *dev,
+ const struct bcm43xx_bbatt *bbatt,
+ const struct bcm43xx_rfatt *rfatt,
+ u8 tx_control)
+{
+ struct bcm43xx_phy *phy = &dev->phy;
+ struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
+ u16 bb, rf;
+ u16 tx_bias, tx_magn;
+
+ bb = bbatt->att;
+ rf = rfatt->att;
+ tx_bias = lo->tx_bias;
+ tx_magn = lo->tx_magn;
+ if (unlikely(tx_bias == 0xFF))
+ tx_bias = 0;
+
+ /* Save the values for later */
+ phy->tx_control = tx_control;
+ memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+ memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
+
+ if (bcm43xx_debug(dev, BCM43xx_DBG_XMITPOWER)) {
+ dprintk(KERN_DEBUG PFX "Tuning TX-power to bbatt(%u), "
+ "rfatt(%u), tx_control(0x%02X), "
+ "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+ bb, rf, tx_control, tx_bias, tx_magn);
+ }
+
+ bcm43xx_phy_set_baseband_attenuation(dev, bb);
+ bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED, BCM43xx_SHM_SH_RFATT, rf);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ bcm43xx_radio_write16(dev, 0x43,
+ (rf & 0x000F) | (tx_control & 0x0070));
+ } else {
+ bcm43xx_radio_write16(dev, 0x43,
+ (bcm43xx_radio_read16(dev, 0x43)
+ & 0xFFF0) | (rf & 0x000F));
+ bcm43xx_radio_write16(dev, 0x52,
+ (bcm43xx_radio_read16(dev, 0x52)
+ & ~0x0070) | (tx_control & 0x0070));
+ }
+ if (has_tx_magnification(phy)) {
+ bcm43xx_radio_write16(dev, 0x52, tx_magn | tx_bias);
+ } else {
+ bcm43xx_radio_write16(dev, 0x52,
+ (bcm43xx_radio_read16(dev, 0x52)
+ & 0xFFF0) | (tx_bias & 0x000F));
+ }
+ if (phy->type == BCM43xx_PHYTYPE_G)
+ bcm43xx_lo_g_adjust(dev);
+}
+
+static void default_baseband_attenuation(struct bcm43xx_wldev *dev,
+ struct bcm43xx_bbatt *bb)
+{
+ struct bcm43xx_phy *phy = &dev->phy;
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+ bb->att = 0;
+ else
+ bb->att = 2;
+}
+
+static void default_radio_attenuation(struct bcm43xx_wldev *dev,
+ struct bcm43xx_rfatt *rf)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct bcm43xx_phy *phy = &dev->phy;
+
+ rf->with_padmix = 0;
+
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+ if (bus->boardinfo.rev < 0x43) {
+ rf->att = 2;
+ return;
+ } else if (bus->boardinfo.rev < 0x51) {
+ rf->att = 3;
+ return;
+ }
+ }
+
+ if (phy->type == BCM43xx_PHYTYPE_A) {
+ rf->att = 0x60;
+ return;
+ }
+
+ switch (phy->radio_ver) {
+ case 0x2053:
+ switch (phy->radio_rev) {
+ case 1:
+ rf->att = 6;
+ return;
+ }
+ break;
+ case 0x2050:
+ switch (phy->radio_rev) {
+ case 0:
+ rf->att = 5;
+ return;
+ case 1:
+ if (phy->type == BCM43xx_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+ bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BU4306)
+ rf->att = 3;
+ else
+ rf->att = 1;
+ } else {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+ bus->boardinfo.rev >= 30)
+ rf->att = 7;
+ else
+ rf->att = 6;
+ }
+ return;
+ case 2:
+ if (phy->type == BCM43xx_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+ bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BU4306)
+ rf->att = 5;
+ else if (bus->chip_id == 0x4320)
+ rf->att = 4;
+ else
+ rf->att = 3;
+ } else
+ rf->att = 6;
+ return;
+ case 3:
+ rf->att = 5;
+ return;
+ case 4:
+ case 5:
+ rf->att = 1;
+ return;
+ case 6:
+ case 7:
+ rf->att = 5;
+ return;
+ case 8:
+ rf->att = 0xA;
+ rf->with_padmix = 1;
+ return;
+ case 9:
+ default:
+ rf->att = 5;
+ return;
+ }
+ }
+ rf->att = 5;
+}
+
+static u16 default_tx_control(struct bcm43xx_wldev *dev)
+{
+ struct bcm43xx_phy *phy = &dev->phy;
+
+ if (phy->radio_ver != 0x2050)
+ return 0;
+ if (phy->radio_rev == 1)
+ return BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX;
+ if (phy->radio_rev < 6)
+ return BCM43xx_TXCTL_PA2DB;
+ if (phy->radio_rev == 8)
+ return BCM43xx_TXCTL_TXMIX;
+ return 0;
+}
+