linux/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Linux LED driver for RTL8187
   4 *
   5 * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
   6 *
   7 * Based on the LED handling in the r8187 driver, which is:
   8 * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
   9 *
  10 * Thanks to Realtek for their support!
  11 */
  12
  13#ifdef CONFIG_RTL8187_LEDS
  14
  15#include <net/mac80211.h>
  16#include <linux/usb.h>
  17#include <linux/eeprom_93cx6.h>
  18
  19#include "rtl8187.h"
  20#include "leds.h"
  21
  22static void led_turn_on(struct work_struct *work)
  23{
  24        /* As this routine does read/write operations on the hardware, it must
  25         * be run from a work queue.
  26         */
  27        u8 reg;
  28        struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
  29                                    led_on.work);
  30        struct rtl8187_led *led = &priv->led_tx;
  31
  32        /* Don't change the LED, when the device is down. */
  33        if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
  34                return ;
  35
  36        /* Skip if the LED is not registered. */
  37        if (!led->dev)
  38                return;
  39        mutex_lock(&priv->conf_mutex);
  40        switch (led->ledpin) {
  41        case LED_PIN_GPIO0:
  42                rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
  43                rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
  44                break;
  45        case LED_PIN_LED0:
  46                reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4);
  47                rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
  48                break;
  49        case LED_PIN_LED1:
  50                reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5);
  51                rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
  52                break;
  53        case LED_PIN_HW:
  54        default:
  55                break;
  56        }
  57        mutex_unlock(&priv->conf_mutex);
  58}
  59
  60static void led_turn_off(struct work_struct *work)
  61{
  62        /* As this routine does read/write operations on the hardware, it must
  63         * be run from a work queue.
  64         */
  65        u8 reg;
  66        struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
  67                                    led_off.work);
  68        struct rtl8187_led *led = &priv->led_tx;
  69
  70        /* Don't change the LED, when the device is down. */
  71        if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
  72                return ;
  73
  74        /* Skip if the LED is not registered. */
  75        if (!led->dev)
  76                return;
  77        mutex_lock(&priv->conf_mutex);
  78        switch (led->ledpin) {
  79        case LED_PIN_GPIO0:
  80                rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
  81                rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
  82                break;
  83        case LED_PIN_LED0:
  84                reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4);
  85                rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
  86                break;
  87        case LED_PIN_LED1:
  88                reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5);
  89                rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
  90                break;
  91        case LED_PIN_HW:
  92        default:
  93                break;
  94        }
  95        mutex_unlock(&priv->conf_mutex);
  96}
  97
  98/* Callback from the LED subsystem. */
  99static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
 100                                   enum led_brightness brightness)
 101{
 102        struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led,
 103                                               led_dev);
 104        struct ieee80211_hw *hw = led->dev;
 105        struct rtl8187_priv *priv;
 106        static bool radio_on;
 107
 108        if (!hw)
 109                return;
 110        priv = hw->priv;
 111        if (led->is_radio) {
 112                if (brightness == LED_FULL) {
 113                        ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
 114                        radio_on = true;
 115                } else if (radio_on) {
 116                        radio_on = false;
 117                        cancel_delayed_work(&priv->led_on);
 118                        ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
 119                }
 120        } else if (radio_on) {
 121                if (brightness == LED_OFF) {
 122                        ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
 123                        /* The LED is off for 1/20 sec - it just blinks. */
 124                        ieee80211_queue_delayed_work(hw, &priv->led_on,
 125                                                     HZ / 20);
 126                } else
 127                        ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
 128        }
 129}
 130
 131static int rtl8187_register_led(struct ieee80211_hw *dev,
 132                                struct rtl8187_led *led, const char *name,
 133                                const char *default_trigger, u8 ledpin,
 134                                bool is_radio)
 135{
 136        int err;
 137        struct rtl8187_priv *priv = dev->priv;
 138
 139        if (led->dev)
 140                return -EEXIST;
 141        if (!default_trigger)
 142                return -EINVAL;
 143        led->dev = dev;
 144        led->ledpin = ledpin;
 145        led->is_radio = is_radio;
 146        strlcpy(led->name, name, sizeof(led->name));
 147
 148        led->led_dev.name = led->name;
 149        led->led_dev.default_trigger = default_trigger;
 150        led->led_dev.brightness_set = rtl8187_led_brightness_set;
 151
 152        err = led_classdev_register(&priv->udev->dev, &led->led_dev);
 153        if (err) {
 154                printk(KERN_INFO "LEDs: Failed to register %s\n", name);
 155                led->dev = NULL;
 156                return err;
 157        }
 158        return 0;
 159}
 160
 161static void rtl8187_unregister_led(struct rtl8187_led *led)
 162{
 163        struct ieee80211_hw *hw = led->dev;
 164        struct rtl8187_priv *priv = hw->priv;
 165
 166        led_classdev_unregister(&led->led_dev);
 167        flush_delayed_work(&priv->led_off);
 168        led->dev = NULL;
 169}
 170
 171void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
 172{
 173        struct rtl8187_priv *priv = dev->priv;
 174        char name[RTL8187_LED_MAX_NAME_LEN + 1];
 175        u8 ledpin;
 176        int err;
 177
 178        /* According to the vendor driver, the LED operation depends on the
 179         * customer ID encoded in the EEPROM
 180         */
 181        printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
 182        switch (custid) {
 183        case EEPROM_CID_RSVD0:
 184        case EEPROM_CID_RSVD1:
 185        case EEPROM_CID_SERCOMM_PS:
 186        case EEPROM_CID_QMI:
 187        case EEPROM_CID_DELL:
 188        case EEPROM_CID_TOSHIBA:
 189                ledpin = LED_PIN_GPIO0;
 190                break;
 191        case EEPROM_CID_ALPHA0:
 192                ledpin = LED_PIN_LED0;
 193                break;
 194        case EEPROM_CID_HW:
 195                ledpin = LED_PIN_HW;
 196                break;
 197        default:
 198                ledpin = LED_PIN_GPIO0;
 199        }
 200
 201        INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
 202        INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
 203
 204        snprintf(name, sizeof(name),
 205                 "rtl8187-%s::radio", wiphy_name(dev->wiphy));
 206        err = rtl8187_register_led(dev, &priv->led_radio, name,
 207                         ieee80211_get_radio_led_name(dev), ledpin, true);
 208        if (err)
 209                return;
 210
 211        snprintf(name, sizeof(name),
 212                 "rtl8187-%s::tx", wiphy_name(dev->wiphy));
 213        err = rtl8187_register_led(dev, &priv->led_tx, name,
 214                         ieee80211_get_tx_led_name(dev), ledpin, false);
 215        if (err)
 216                goto err_tx;
 217
 218        snprintf(name, sizeof(name),
 219                 "rtl8187-%s::rx", wiphy_name(dev->wiphy));
 220        err = rtl8187_register_led(dev, &priv->led_rx, name,
 221                         ieee80211_get_rx_led_name(dev), ledpin, false);
 222        if (!err)
 223                return;
 224
 225        /* registration of RX LED failed - unregister */
 226        rtl8187_unregister_led(&priv->led_tx);
 227err_tx:
 228        rtl8187_unregister_led(&priv->led_radio);
 229}
 230
 231void rtl8187_leds_exit(struct ieee80211_hw *dev)
 232{
 233        struct rtl8187_priv *priv = dev->priv;
 234
 235        rtl8187_unregister_led(&priv->led_radio);
 236        rtl8187_unregister_led(&priv->led_rx);
 237        rtl8187_unregister_led(&priv->led_tx);
 238        cancel_delayed_work_sync(&priv->led_off);
 239        cancel_delayed_work_sync(&priv->led_on);
 240}
 241#endif /* def CONFIG_RTL8187_LEDS */
 242
 243