548-ath9k_enable_gpio_chip.patch 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. From: Michal Cieslakiewicz <[email protected]>
  2. Date: Sun, 31 Jan 2016 21:01:31 +0100
  3. Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO
  4. Enable access to GPIO chip and its pins for Atheros AR92xx
  5. wireless devices. For now AR9285 and AR9287 are supported.
  6. Signed-off-by: Michal Cieslakiewicz <[email protected]>
  7. Signed-off-by: Felix Fietkau <[email protected]>
  8. ---
  9. --- a/drivers/net/wireless/ath/ath9k/ath9k.h
  10. +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
  11. @@ -24,6 +24,7 @@
  12. #include <linux/completion.h>
  13. #include <linux/time.h>
  14. #include <linux/hw_random.h>
  15. +#include <linux/gpio/driver.h>
  16. #include "common.h"
  17. #include "debug.h"
  18. @@ -1001,6 +1002,14 @@ struct ath_led {
  19. struct led_classdev cdev;
  20. };
  21. +#ifdef CONFIG_GPIOLIB
  22. +struct ath9k_gpio_chip {
  23. + struct ath_softc *sc;
  24. + char label[32];
  25. + struct gpio_chip gchip;
  26. +};
  27. +#endif
  28. +
  29. struct ath_softc {
  30. struct ieee80211_hw *hw;
  31. struct device *dev;
  32. @@ -1058,6 +1067,9 @@ struct ath_softc {
  33. #ifdef CPTCFG_MAC80211_LEDS
  34. const char *led_default_trigger;
  35. struct list_head leds;
  36. +#ifdef CONFIG_GPIOLIB
  37. + struct ath9k_gpio_chip *gpiochip;
  38. +#endif
  39. #endif
  40. #ifdef CPTCFG_ATH9K_DEBUGFS
  41. --- a/drivers/net/wireless/ath/ath9k/gpio.c
  42. +++ b/drivers/net/wireless/ath/ath9k/gpio.c
  43. @@ -16,13 +16,130 @@
  44. #include "ath9k.h"
  45. #include <linux/ath9k_platform.h>
  46. +#include <linux/gpio.h>
  47. +
  48. +#ifdef CPTCFG_MAC80211_LEDS
  49. +
  50. +#ifdef CONFIG_GPIOLIB
  51. +
  52. +/***************/
  53. +/* GPIO Chip */
  54. +/***************/
  55. +
  56. +/* gpio_chip handler : set GPIO to input */
  57. +static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
  58. +{
  59. + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
  60. + gchip);
  61. +
  62. + ath9k_hw_gpio_request_in(gc->sc->sc_ah, offset, "ath9k-gpio");
  63. +
  64. + return 0;
  65. +}
  66. +
  67. +/* gpio_chip handler : set GPIO to output */
  68. +static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
  69. + int value)
  70. +{
  71. + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
  72. + gchip);
  73. +
  74. + ath9k_hw_gpio_request_out(gc->sc->sc_ah, offset, "ath9k-gpio",
  75. + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
  76. + ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
  77. +
  78. + return 0;
  79. +}
  80. +
  81. +/* gpio_chip handler : query GPIO direction (0=out, 1=in) */
  82. +static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset)
  83. +{
  84. + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
  85. + gchip);
  86. + struct ath_hw *ah = gc->sc->sc_ah;
  87. +
  88. + return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
  89. +}
  90. +
  91. +/* gpio_chip handler : get GPIO pin value */
  92. +static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
  93. +{
  94. + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
  95. + gchip);
  96. +
  97. + return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
  98. +}
  99. +
  100. +/* gpio_chip handler : set GPIO pin to value */
  101. +static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
  102. + int value)
  103. +{
  104. + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
  105. + gchip);
  106. +
  107. + ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
  108. +}
  109. +
  110. +/* register GPIO chip */
  111. +static void ath9k_register_gpio_chip(struct ath_softc *sc)
  112. +{
  113. + struct ath9k_gpio_chip *gc;
  114. + struct ath_hw *ah = sc->sc_ah;
  115. +
  116. + gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
  117. + if (!gc)
  118. + return;
  119. +
  120. + gc->sc = sc;
  121. + snprintf(gc->label, sizeof(gc->label), "ath9k-%s",
  122. + wiphy_name(sc->hw->wiphy));
  123. +
  124. + gc->gchip.label = gc->label;
  125. + gc->gchip.base = -1; /* determine base automatically */
  126. + gc->gchip.ngpio = ah->caps.num_gpio_pins;
  127. + gc->gchip.direction_input = ath9k_gpio_pin_cfg_input;
  128. + gc->gchip.direction_output = ath9k_gpio_pin_cfg_output;
  129. + gc->gchip.get_direction = ath9k_gpio_pin_get_dir;
  130. + gc->gchip.get = ath9k_gpio_pin_get;
  131. + gc->gchip.set = ath9k_gpio_pin_set;
  132. +
  133. + if (gpiochip_add(&gc->gchip)) {
  134. + kfree(gc);
  135. + return;
  136. + }
  137. +
  138. + sc->gpiochip = gc;
  139. +}
  140. +
  141. +/* remove GPIO chip */
  142. +static void ath9k_unregister_gpio_chip(struct ath_softc *sc)
  143. +{
  144. + struct ath9k_gpio_chip *gc = sc->gpiochip;
  145. +
  146. + if (!gc)
  147. + return;
  148. +
  149. + gpiochip_remove(&gc->gchip);
  150. + kfree(gc);
  151. + sc->gpiochip = NULL;
  152. +}
  153. +
  154. +#else /* CONFIG_GPIOLIB */
  155. +
  156. +static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
  157. +{
  158. +}
  159. +
  160. +static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
  161. +{
  162. +}
  163. +
  164. +#endif /* CONFIG_GPIOLIB */
  165. /********************************/
  166. /* LED functions */
  167. /********************************/
  168. -#ifdef CPTCFG_MAC80211_LEDS
  169. -
  170. static void ath_fill_led_pin(struct ath_softc *sc)
  171. {
  172. struct ath_hw *ah = sc->sc_ah;
  173. @@ -80,6 +197,12 @@ static int ath_add_led(struct ath_softc
  174. else
  175. ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
  176. +#ifdef CONFIG_GPIOLIB
  177. + /* If there is GPIO chip configured, reserve LED pin */
  178. + if (sc->gpiochip)
  179. + gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
  180. +#endif
  181. +
  182. return 0;
  183. }
  184. @@ -136,17 +259,24 @@ void ath_deinit_leds(struct ath_softc *s
  185. while (!list_empty(&sc->leds)) {
  186. led = list_first_entry(&sc->leds, struct ath_led, list);
  187. +#ifdef CONFIG_GPIOLIB
  188. + /* If there is GPIO chip configured, free LED pin */
  189. + if (sc->gpiochip)
  190. + gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio);
  191. +#endif
  192. list_del(&led->list);
  193. ath_led_brightness(&led->cdev, LED_OFF);
  194. led_classdev_unregister(&led->cdev);
  195. ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
  196. kfree(led);
  197. }
  198. + ath9k_unregister_gpio_chip(sc);
  199. }
  200. void ath_init_leds(struct ath_softc *sc)
  201. {
  202. struct ath9k_platform_data *pdata = sc->dev->platform_data;
  203. + struct device_node *np = sc->dev->of_node;
  204. char led_name[32];
  205. const char *trigger;
  206. int i;
  207. @@ -156,6 +286,15 @@ void ath_init_leds(struct ath_softc *sc)
  208. if (AR_SREV_9100(sc->sc_ah))
  209. return;
  210. + if (!np)
  211. + ath9k_register_gpio_chip(sc);
  212. +
  213. + /* setup gpio controller only if requested and skip the led_pin setup */
  214. + if (of_property_read_bool(np, "gpio-controller")) {
  215. + ath9k_register_gpio_chip(sc);
  216. + return;
  217. + }
  218. +
  219. ath_fill_led_pin(sc);
  220. if (pdata && pdata->leds && pdata->num_leds)
  221. @@ -180,6 +319,7 @@ void ath_init_leds(struct ath_softc *sc)
  222. ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
  223. !sc->sc_ah->config.led_active_high);
  224. }
  225. +
  226. #endif
  227. /*******************/