leds.c (6419B)
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