243 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Linux LED driver for RTL81874 *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_LEDS14 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 must25 * 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 must63 * 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 } else127 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 strscpy(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 the179 * customer ID encoded in the EEPROM180 */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