From: Michal Cieslakiewicz Subject: [PATCH v5 5/8] mac80211: ath9k: enable GPIO buttons Enable platform-defined GPIO button support for ath9k device. Key poller is activated for attached platform buttons. Requires ath9k GPIO chip access. Signed-off-by: Michal Cieslakiewicz --- drivers/net/wireless/ath/ath9k/ath9k.h | 16 ++++++ drivers/net/wireless/ath/ath9k/gpio.c | 77 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/init.c | 2 include/linux/ath9k_platform.h | 4 + 4 files changed, 99 insertions(+) --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -825,6 +825,13 @@ int ath_create_gpio_led(struct ath_softc void ath9k_register_gpio_chip(struct ath_softc *sc); void ath9k_unregister_gpio_chip(struct ath_softc *sc); +/******************/ +/* GPIO Buttons */ +/******************/ + +void ath9k_init_buttons(struct ath_softc *sc); +void ath9k_deinit_buttons(struct ath_softc *sc); + #else static inline void ath_init_leds(struct ath_softc *sc) { @@ -844,6 +851,14 @@ static inline void ath9k_register_gpio_c static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc) { } + +static inline void ath9k_init_buttons(struct ath_softc *sc) +{ +} + +static inline void ath9k_deinit_buttons(struct ath_softc *sc) +{ +} #endif /************************/ @@ -1040,6 +1055,7 @@ struct ath_softc { const char *led_default_trigger; struct list_head leds; struct ath9k_gpio_chip *gpiochip; + struct platform_device *btnpdev; /* gpio-keys-polled */ #endif #ifdef CPTCFG_ATH9K_DEBUGFS --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -24,6 +24,8 @@ #ifdef CPTCFG_MAC80211_LEDS #include +#include +#include static void ath_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) @@ -159,7 +161,7 @@ void ath_init_leds(struct ath_softc *sc) ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, !sc->sc_ah->config.led_active_high); - if (!pdata) + if (!pdata || !pdata->leds || !pdata->num_leds) return; for (i = 0; i < pdata->num_leds; i++) @@ -307,6 +309,63 @@ void ath9k_unregister_gpio_chip(struct a sc->gpiochip = NULL; } +/******************/ +/* GPIO Buttons */ +/******************/ + +/* add GPIO buttons */ +void ath9k_init_buttons(struct ath_softc *sc) +{ + struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct platform_device *pdev; + struct gpio_keys_platform_data gkpdata; + struct gpio_keys_button *bt; + int i; + + if (!sc->gpiochip) + return; + + if (!pdata || !pdata->btns || !pdata->num_btns) + return; + + bt = devm_kmemdup(sc->dev, pdata->btns, + pdata->num_btns * sizeof(struct gpio_keys_button), + GFP_KERNEL); + if (!bt) + return; + + for (i = 0; i < pdata->num_btns; i++) { + ath9k_hw_cfg_gpio_input(sc->sc_ah, pdata->btns[i].gpio); + bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio; + } + + memset(&gkpdata, 0, sizeof(struct gpio_keys_platform_data)); + gkpdata.buttons = bt; + gkpdata.nbuttons = pdata->num_btns; + gkpdata.poll_interval = pdata->btn_poll_interval; + + pdev = platform_device_register_data(sc->dev, "gpio-keys-polled", + PLATFORM_DEVID_AUTO, &gkpdata, + sizeof(gkpdata)); + if (!IS_ERR_OR_NULL(pdev)) + sc->btnpdev = pdev; + else { + sc->btnpdev = NULL; + devm_kfree(sc->dev, bt); + } +} + +/* remove GPIO buttons */ +void ath9k_deinit_buttons(struct ath_softc *sc) +{ + if (!sc->gpiochip || !sc->btnpdev) + return; + + platform_device_unregister(sc->btnpdev); + + sc->btnpdev = NULL; +} + #endif /*******************/ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -977,6 +977,7 @@ int ath9k_init_device(u16 devid, struct ath9k_register_gpio_chip(sc); ath_init_leds(sc); + ath9k_init_buttons(sc); ath_start_rfkill_poll(sc); return 0; @@ -1022,6 +1023,7 @@ void ath9k_deinit_device(struct ath_soft ath9k_ps_wakeup(sc); wiphy_rfkill_stop_polling(sc->hw->wiphy); + ath9k_deinit_buttons(sc); ath_deinit_leds(sc); ath9k_unregister_gpio_chip(sc); --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -46,6 +46,10 @@ struct ath9k_platform_data { int num_leds; const struct gpio_led *leds; const char *led_name; + + unsigned num_btns; + const struct gpio_keys_button *btns; + unsigned btn_poll_interval; }; #endif /* _LINUX_ATH9K_PLATFORM_H */