0001
0002
0003
0004
0005
0006 #include <linux/leds.h>
0007 #include "iwl-io.h"
0008 #include "iwl-csr.h"
0009 #include "mvm.h"
0010
0011 static void iwl_mvm_send_led_fw_cmd(struct iwl_mvm *mvm, bool on)
0012 {
0013 struct iwl_led_cmd led_cmd = {
0014 .status = cpu_to_le32(on),
0015 };
0016 struct iwl_host_cmd cmd = {
0017 .id = WIDE_ID(LONG_GROUP, LEDS_CMD),
0018 .len = { sizeof(led_cmd), },
0019 .data = { &led_cmd, },
0020 .flags = CMD_ASYNC,
0021 };
0022 int err;
0023
0024 if (!iwl_mvm_firmware_running(mvm))
0025 return;
0026
0027 err = iwl_mvm_send_cmd(mvm, &cmd);
0028
0029 if (err)
0030 IWL_WARN(mvm, "LED command failed: %d\n", err);
0031 }
0032
0033 static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on)
0034 {
0035 if (fw_has_capa(&mvm->fw->ucode_capa,
0036 IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT)) {
0037 iwl_mvm_send_led_fw_cmd(mvm, on);
0038 return;
0039 }
0040
0041 iwl_write32(mvm->trans, CSR_LED_REG,
0042 on ? CSR_LED_REG_TURN_ON : CSR_LED_REG_TURN_OFF);
0043 }
0044
0045 static void iwl_led_brightness_set(struct led_classdev *led_cdev,
0046 enum led_brightness brightness)
0047 {
0048 struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led);
0049
0050 iwl_mvm_led_set(mvm, brightness > 0);
0051 }
0052
0053 int iwl_mvm_leds_init(struct iwl_mvm *mvm)
0054 {
0055 int mode = iwlwifi_mod_params.led_mode;
0056 int ret;
0057
0058 switch (mode) {
0059 case IWL_LED_BLINK:
0060 IWL_ERR(mvm, "Blink led mode not supported, used default\n");
0061 fallthrough;
0062 case IWL_LED_DEFAULT:
0063 case IWL_LED_RF_STATE:
0064 mode = IWL_LED_RF_STATE;
0065 break;
0066 case IWL_LED_DISABLE:
0067 IWL_INFO(mvm, "Led disabled\n");
0068 return 0;
0069 default:
0070 return -EINVAL;
0071 }
0072
0073 mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
0074 wiphy_name(mvm->hw->wiphy));
0075 if (!mvm->led.name)
0076 return -ENOMEM;
0077
0078 mvm->led.brightness_set = iwl_led_brightness_set;
0079 mvm->led.max_brightness = 1;
0080
0081 if (mode == IWL_LED_RF_STATE)
0082 mvm->led.default_trigger =
0083 ieee80211_get_radio_led_name(mvm->hw);
0084
0085 ret = led_classdev_register(mvm->trans->dev, &mvm->led);
0086 if (ret) {
0087 kfree(mvm->led.name);
0088 IWL_INFO(mvm, "Failed to enable led\n");
0089 return ret;
0090 }
0091
0092 mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
0093 return 0;
0094 }
0095
0096 void iwl_mvm_leds_sync(struct iwl_mvm *mvm)
0097 {
0098 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))
0099 return;
0100
0101
0102
0103
0104
0105 if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000)
0106 return;
0107
0108 iwl_mvm_led_set(mvm, mvm->led.brightness > 0);
0109 }
0110
0111 void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
0112 {
0113 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))
0114 return;
0115
0116 led_classdev_unregister(&mvm->led);
0117 kfree(mvm->led.name);
0118 mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
0119 }