120 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2012-2014, 2018-2019 Intel Corporation4 * Copyright (C) 2017 Intel Deutschland GmbH5 */6#include <linux/leds.h>7#include "iwl-io.h"8#include "iwl-csr.h"9#include "mvm.h"10 11static void iwl_mvm_send_led_fw_cmd(struct iwl_mvm *mvm, bool on)12{13 struct iwl_led_cmd led_cmd = {14 .status = cpu_to_le32(on),15 };16 struct iwl_host_cmd cmd = {17 .id = WIDE_ID(LONG_GROUP, LEDS_CMD),18 .len = { sizeof(led_cmd), },19 .data = { &led_cmd, },20 .flags = CMD_ASYNC,21 };22 int err;23 24 if (!iwl_mvm_firmware_running(mvm))25 return;26 27 err = iwl_mvm_send_cmd(mvm, &cmd);28 29 if (err)30 IWL_WARN(mvm, "LED command failed: %d\n", err);31}32 33static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on)34{35 if (fw_has_capa(&mvm->fw->ucode_capa,36 IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT)) {37 iwl_mvm_send_led_fw_cmd(mvm, on);38 return;39 }40 41 iwl_write32(mvm->trans, CSR_LED_REG,42 on ? CSR_LED_REG_TURN_ON : CSR_LED_REG_TURN_OFF);43}44 45static void iwl_led_brightness_set(struct led_classdev *led_cdev,46 enum led_brightness brightness)47{48 struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led);49 50 iwl_mvm_led_set(mvm, brightness > 0);51}52 53int iwl_mvm_leds_init(struct iwl_mvm *mvm)54{55 int mode = iwlwifi_mod_params.led_mode;56 int ret;57 58 switch (mode) {59 case IWL_LED_BLINK:60 IWL_ERR(mvm, "Blink led mode not supported, used default\n");61 fallthrough;62 case IWL_LED_DEFAULT:63 case IWL_LED_RF_STATE:64 mode = IWL_LED_RF_STATE;65 break;66 case IWL_LED_DISABLE:67 IWL_INFO(mvm, "Led disabled\n");68 return 0;69 default:70 return -EINVAL;71 }72 73 mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",74 wiphy_name(mvm->hw->wiphy));75 if (!mvm->led.name)76 return -ENOMEM;77 78 mvm->led.brightness_set = iwl_led_brightness_set;79 mvm->led.max_brightness = 1;80 81 if (mode == IWL_LED_RF_STATE)82 mvm->led.default_trigger =83 ieee80211_get_radio_led_name(mvm->hw);84 85 ret = led_classdev_register(mvm->trans->dev, &mvm->led);86 if (ret) {87 kfree(mvm->led.name);88 IWL_INFO(mvm, "Failed to enable led\n");89 return ret;90 }91 92 mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;93 return 0;94}95 96void iwl_mvm_leds_sync(struct iwl_mvm *mvm)97{98 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))99 return;100 101 /*102 * if we control through the register, we're doing it103 * even when the firmware isn't up, so no need to sync104 */105 if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000)106 return;107 108 iwl_mvm_led_set(mvm, mvm->led.brightness > 0);109}110 111void iwl_mvm_leds_exit(struct iwl_mvm *mvm)112{113 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))114 return;115 116 led_classdev_unregister(&mvm->led);117 kfree(mvm->led.name);118 mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;119}120