ath9k: make GPIO API to support both of WMAC and SOC
[cascardo/linux.git] / drivers / net / wireless / ath / ath9k / hw.c
index f14242b..7f39b13 100644 (file)
@@ -1582,7 +1582,8 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
                if (!(gpio_mask & 1))
                        continue;
 
-               ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+               ath9k_hw_gpio_request_out(ah, i, NULL,
+                                         AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
                ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
        }
 }
@@ -1958,7 +1959,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_qos(ah);
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+               ath9k_hw_gpio_request_in(ah, ah->rfkill_gpio, "ath9k-rfkill");
 
        ath9k_hw_init_global_settings(ah);
 
@@ -2654,8 +2655,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 /* GPIO / RFKILL / Antennae */
 /****************************/
 
-static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
-                                        u32 gpio, u32 type)
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
 {
        int addr;
        u32 gpio_shift, tmp;
@@ -2669,8 +2669,8 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
 
        gpio_shift = (gpio % 6) * 5;
 
-       if (AR_SREV_9280_20_OR_LATER(ah)
-           || (addr != AR_GPIO_OUTPUT_MUX1)) {
+       if (AR_SREV_9280_20_OR_LATER(ah) ||
+           (addr != AR_GPIO_OUTPUT_MUX1)) {
                REG_RMW(ah, addr, (type << gpio_shift),
                        (0x1f << gpio_shift));
        } else {
@@ -2682,106 +2682,144 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
        }
 }
 
-void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
+/* BSP should set the corresponding MUX register correctly.
+ */
+static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
+                                 const char *label)
 {
-       u32 gpio_shift;
+       if (ah->caps.gpio_requested & BIT(gpio))
+               return;
 
-       BUG_ON(gpio >= ah->caps.num_gpio_pins);
+       /* may be requested by BSP, free anyway */
+       gpio_free(gpio);
 
-       if (AR_DEVID_7010(ah)) {
-               gpio_shift = gpio;
-               REG_RMW(ah, AR7010_GPIO_OE,
-                       (AR7010_GPIO_OE_AS_INPUT << gpio_shift),
-                       (AR7010_GPIO_OE_MASK << gpio_shift));
+       if (gpio_request_one(gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label))
                return;
-       }
 
-       gpio_shift = gpio << 1;
-       REG_RMW(ah,
-               AR_GPIO_OE_OUT,
-               (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
-               (AR_GPIO_OE_OUT_DRV << gpio_shift));
+       ah->caps.gpio_requested |= BIT(gpio);
 }
-EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input);
 
-u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
+static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
+                                  u32 ah_signal_type)
 {
-#define MS_REG_READ(x, y) \
-       (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
-
-       if (gpio >= ah->caps.num_gpio_pins)
-               return 0xffffffff;
+       u32 gpio_set, gpio_shift = gpio;
 
        if (AR_DEVID_7010(ah)) {
-               u32 val;
-               val = REG_READ(ah, AR7010_GPIO_IN);
-               return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
-       } else if (AR_SREV_9300_20_OR_LATER(ah))
-               return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
-                       AR_GPIO_BIT(gpio)) != 0;
-       else if (AR_SREV_9271(ah))
-               return MS_REG_READ(AR9271, gpio) != 0;
-       else if (AR_SREV_9287_11_OR_LATER(ah))
-               return MS_REG_READ(AR9287, gpio) != 0;
-       else if (AR_SREV_9285_12_OR_LATER(ah))
-               return MS_REG_READ(AR9285, gpio) != 0;
-       else if (AR_SREV_9280_20_OR_LATER(ah))
-               return MS_REG_READ(AR928X, gpio) != 0;
-       else
-               return MS_REG_READ(AR, gpio) != 0;
+               gpio_set = out ?
+                       AR7010_GPIO_OE_AS_OUTPUT : AR7010_GPIO_OE_AS_INPUT;
+               REG_RMW(ah, AR7010_GPIO_OE, gpio_set << gpio_shift,
+                       AR7010_GPIO_OE_MASK << gpio_shift);
+       } else if (AR_SREV_SOC(ah)) {
+               gpio_set = out ? 1 : 0;
+               REG_RMW(ah, AR_GPIO_OE_OUT, gpio_set << gpio_shift,
+                       gpio_set << gpio_shift);
+       } else {
+               gpio_shift = gpio << 1;
+               gpio_set = out ?
+                       AR_GPIO_OE_OUT_DRV_ALL : AR_GPIO_OE_OUT_DRV_NO;
+               REG_RMW(ah, AR_GPIO_OE_OUT, gpio_set << gpio_shift,
+                       AR_GPIO_OE_OUT_DRV << gpio_shift);
+
+               if (out)
+                       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+       }
 }
-EXPORT_SYMBOL(ath9k_hw_gpio_get);
 
-void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
-                        u32 ah_signal_type)
+static void ath9k_hw_gpio_request(struct ath_hw *ah, u32 gpio, bool out,
+                                 const char *label, u32 ah_signal_type)
 {
-       u32 gpio_shift;
+       WARN_ON(gpio >= ah->caps.num_gpio_pins);
 
-       if (AR_DEVID_7010(ah)) {
-               gpio_shift = gpio;
-               REG_RMW(ah, AR7010_GPIO_OE,
-                       (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
-                       (AR7010_GPIO_OE_MASK << gpio_shift));
-               return;
-       }
+       if (BIT(gpio) & ah->caps.gpio_mask)
+               ath9k_hw_gpio_cfg_wmac(ah, gpio, out, ah_signal_type);
+       else if (AR_SREV_SOC(ah))
+               ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
+       else
+               WARN_ON(1);
+}
 
-       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
-       gpio_shift = 2 * gpio;
-       REG_RMW(ah,
-               AR_GPIO_OE_OUT,
-               (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
-               (AR_GPIO_OE_OUT_DRV << gpio_shift));
+void ath9k_hw_gpio_request_in(struct ath_hw *ah, u32 gpio, const char *label)
+{
+       ath9k_hw_gpio_request(ah, gpio, false, label, 0);
 }
-EXPORT_SYMBOL(ath9k_hw_cfg_output);
+EXPORT_SYMBOL(ath9k_hw_gpio_request_in);
 
-void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
+void ath9k_hw_gpio_request_out(struct ath_hw *ah, u32 gpio, const char *label,
+                              u32 ah_signal_type)
 {
-       if (AR_DEVID_7010(ah)) {
-               val = val ? 0 : 1;
-               REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
-                       AR_GPIO_BIT(gpio));
+       ath9k_hw_gpio_request(ah, gpio, true, label, ah_signal_type);
+}
+EXPORT_SYMBOL(ath9k_hw_gpio_request_out);
+
+void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
+{
+       if (!AR_SREV_SOC(ah))
                return;
+
+       WARN_ON(gpio >= ah->caps.num_gpio_pins);
+
+       if (ah->caps.gpio_requested & BIT(gpio)) {
+               gpio_free(gpio);
+               ah->caps.gpio_requested &= ~BIT(gpio);
        }
+}
+EXPORT_SYMBOL(ath9k_hw_gpio_free);
 
-       if (AR_SREV_9271(ah))
-               val = ~val;
+u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
+{
+       u32 val = 0xffffffff;
 
-       if ((1 << gpio) & AR_GPIO_OE_OUT_MASK)
-               REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
-                       AR_GPIO_BIT(gpio));
-       else
-               gpio_set_value(gpio, val & 1);
+#define MS_REG_READ(x, y) \
+       (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & BIT(y))
+
+       WARN_ON(gpio >= ah->caps.num_gpio_pins);
+
+       if (BIT(gpio) & ah->caps.gpio_mask) {
+               if (AR_SREV_9271(ah))
+                       val = MS_REG_READ(AR9271, gpio);
+               else if (AR_SREV_9287(ah))
+                       val = MS_REG_READ(AR9287, gpio);
+               else if (AR_SREV_9285(ah))
+                       val = MS_REG_READ(AR9285, gpio);
+               else if (AR_SREV_9280(ah))
+                       val = MS_REG_READ(AR928X, gpio);
+               else if (AR_DEVID_7010(ah))
+                       val = REG_READ(ah, AR7010_GPIO_IN) & BIT(gpio);
+               else if (AR_SREV_9300_20_OR_LATER(ah))
+                       val = REG_READ(ah, AR_GPIO_IN) & BIT(gpio);
+               else
+                       val = MS_REG_READ(AR, gpio);
+       } else if (BIT(gpio) & ah->caps.gpio_requested) {
+               val = gpio_get_value(gpio) & BIT(gpio);
+       } else {
+               WARN_ON(1);
+       }
+
+       return val;
 }
-EXPORT_SYMBOL(ath9k_hw_set_gpio);
+EXPORT_SYMBOL(ath9k_hw_gpio_get);
 
-void ath9k_hw_request_gpio(struct ath_hw *ah, u32 gpio, const char *label)
+void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 {
-       if (gpio >= ah->caps.num_gpio_pins)
-               return;
+       WARN_ON(gpio >= ah->caps.num_gpio_pins);
 
-       gpio_request_one(gpio, GPIOF_DIR_OUT | GPIOF_INIT_LOW, label);
+       if (AR_DEVID_7010(ah) || AR_SREV_9271(ah))
+               val = !val;
+       else
+               val = !!val;
+
+       if (BIT(gpio) & ah->caps.gpio_mask) {
+               u32 out_addr = AR_DEVID_7010(ah) ?
+                       AR7010_GPIO_OUT : AR_GPIO_IN_OUT;
+
+               REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
+       } else if (BIT(gpio) & ah->caps.gpio_requested) {
+               gpio_set_value(gpio, val);
+       } else {
+               WARN_ON(1);
+       }
 }
-EXPORT_SYMBOL(ath9k_hw_request_gpio);
+EXPORT_SYMBOL(ath9k_hw_set_gpio);
 
 void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
 {