rt2x00: Implement tx power temperature compensation

rt2800 devices should adjust their tx power in accordance with the
eeproms temperature calibration values. Add a new driver callback
gain_calibration that is called every 4 seconds.

The rt2800 gain calibration routine simply runs the tx power
configuration that takes care of calculating the temperature
compensation delta.

We don't need to synchronize the calls to rt2800_config_txpower
as they should all happen from mac80211's single threaded workqueue.

Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index fc8cee9..128b361 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -446,8 +446,46 @@
 					     WATCHDOG_INTERVAL);
 }
 
+void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev)
+{
+	struct link *link = &rt2x00dev->link;
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+	    rt2x00dev->ops->lib->gain_calibration)
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->agc_work,
+					     AGC_INTERVAL);
+}
+
+void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
+{
+	cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
+}
+
+static void rt2x00link_agc(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, link.agc_work.work);
+	struct link *link = &rt2x00dev->link;
+
+	/*
+	 * When the radio is shutting down we should
+	 * immediately cease the watchdog monitoring.
+	 */
+	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
+
+	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+		ieee80211_queue_delayed_work(rt2x00dev->hw,
+					     &link->agc_work,
+					     AGC_INTERVAL);
+}
+
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
+	INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
 	INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
 }