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