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