brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · f7d95c9 Raw
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