Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10d599ad authored by Maya Erez's avatar Maya Erez Committed by Kalle Valo
Browse files

wil6210: add support for device led configuration



Add the ability to configure the device led to be used for notifying
the AP activity (60G device supports leds 0-2).
The host can also configure the blinking frequency of the led in
three states.

Signed-off-by: default avatarMaya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 41842dc1
Loading
Loading
Loading
Loading
+115 −0
Original line number Diff line number Diff line
@@ -1441,6 +1441,118 @@ static const struct file_operations fops_sta = {
	.llseek		= seq_lseek,
};

static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
				     size_t count, loff_t *ppos)
{
	char buf[80];
	int n;

	n = snprintf(buf, sizeof(buf),
		     "led_id is set to %d, echo 1 to enable, 0 to disable\n",
		     led_id);

	n = min_t(int, n, sizeof(buf));

	return simple_read_from_buffer(user_buf, count, ppos,
				       buf, n);
}

static ssize_t wil_write_file_led_cfg(struct file *file,
				      const char __user *buf_,
				      size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	int val;
	int rc;

	rc = kstrtoint_from_user(buf_, count, 0, &val);
	if (rc) {
		wil_err(wil, "Invalid argument\n");
		return rc;
	}

	wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id);
	rc = wmi_led_cfg(wil, val);
	if (rc) {
		wil_info(wil, "%s led %d failed\n",
			 val ? "Enabling" : "Disabling", led_id);
		return rc;
	}

	return count;
}

static const struct file_operations fops_led_cfg = {
	.read = wil_read_file_led_cfg,
	.write = wil_write_file_led_cfg,
	.open  = simple_open,
};

/* led_blink_time, write:
 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast>
 */
static ssize_t wil_write_led_blink_time(struct file *file,
					const char __user *buf,
					size_t len, loff_t *ppos)
{
	int rc;
	char *kbuf = kmalloc(len + 1, GFP_KERNEL);

	if (!kbuf)
		return -ENOMEM;

	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
	if (rc != len) {
		kfree(kbuf);
		return rc >= 0 ? -EIO : rc;
	}

	kbuf[len] = '\0';
	rc = sscanf(kbuf, "%d %d %d %d %d %d",
		    &led_blink_time[WIL_LED_TIME_SLOW].on_ms,
		    &led_blink_time[WIL_LED_TIME_SLOW].off_ms,
		    &led_blink_time[WIL_LED_TIME_MED].on_ms,
		    &led_blink_time[WIL_LED_TIME_MED].off_ms,
		    &led_blink_time[WIL_LED_TIME_FAST].on_ms,
		    &led_blink_time[WIL_LED_TIME_FAST].off_ms);
	kfree(kbuf);

	if (rc < 0)
		return rc;
	if (rc < 6)
		return -EINVAL;

	return len;
}

static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf,
				       size_t count, loff_t *ppos)
{
	static char text[400];

	snprintf(text, sizeof(text),
		 "To set led blink on/off time variables write:\n"
		 "<blink_on_slow> <blink_off_slow> <blink_on_med> "
		 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n"
		 "The current values are:\n"
		 "%d %d %d %d %d %d\n",
		 led_blink_time[WIL_LED_TIME_SLOW].on_ms,
		 led_blink_time[WIL_LED_TIME_SLOW].off_ms,
		 led_blink_time[WIL_LED_TIME_MED].on_ms,
		 led_blink_time[WIL_LED_TIME_MED].off_ms,
		 led_blink_time[WIL_LED_TIME_FAST].on_ms,
		 led_blink_time[WIL_LED_TIME_FAST].off_ms);

	return simple_read_from_buffer(user_buf, count, ppos, text,
				       sizeof(text));
}

static const struct file_operations fops_led_blink_time = {
	.read = wil_read_led_blink_time,
	.write = wil_write_led_blink_time,
	.open  = simple_open,
};

/*----------------*/
static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
				       struct dentry *dbg)
@@ -1489,6 +1601,8 @@ static const struct {
	{"link",	S_IRUGO,		&fops_link},
	{"info",	S_IRUGO,		&fops_info},
	{"recovery",	S_IRUGO | S_IWUSR,	&fops_recovery},
	{"led_cfg",	S_IRUGO | S_IWUSR,	&fops_led_cfg},
	{"led_blink_time",	S_IRUGO | S_IWUSR,	&fops_led_blink_time},
};

static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -1551,6 +1665,7 @@ static const struct dbg_off dbg_statics[] = {
	{"mem_addr",	S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
	{"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh,
	 doff_u32},
	{"led_polarity", S_IRUGO | S_IWUSR, (ulong)&led_polarity, doff_u8},
	{},
};

+3 −0
Original line number Diff line number Diff line
@@ -841,6 +841,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
	wil_bcast_fini(wil);

	/* Disable device led before reset*/
	wmi_led_cfg(wil, false);

	/* prevent NAPI from being scheduled and prevent wmi commands */
	mutex_lock(&wil->wmi_mutex);
	bitmap_zero(wil->status, wil_status_last);
+25 −0
Original line number Diff line number Diff line
@@ -546,6 +546,30 @@ struct wil_blob_wrapper {
	struct debugfs_blob_wrapper blob;
};

#define WIL_LED_MAX_ID			(2)
#define WIL_LED_INVALID_ID		(0xF)
#define WIL_LED_BLINK_ON_SLOW_MS	(300)
#define WIL_LED_BLINK_OFF_SLOW_MS	(300)
#define WIL_LED_BLINK_ON_MED_MS		(200)
#define WIL_LED_BLINK_OFF_MED_MS	(200)
#define WIL_LED_BLINK_ON_FAST_MS	(100)
#define WIL_LED_BLINK_OFF_FAST_MS	(100)
enum {
	WIL_LED_TIME_SLOW = 0,
	WIL_LED_TIME_MED,
	WIL_LED_TIME_FAST,
	WIL_LED_TIME_LAST,
};

struct blink_on_off_time {
	u32 on_ms;
	u32 off_ms;
};

extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
extern u8 led_id;
extern u8 led_polarity;

struct wil6210_priv {
	struct pci_dev *pdev;
	struct wireless_dev *wdev;
@@ -834,6 +858,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
		  u8 chan, u8 hidden_ssid, u8 is_go);
int wmi_pcp_stop(struct wil6210_priv *wil);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
			u16 reason_code, bool from_event);
void wil_probe_client_flush(struct wil6210_priv *wil);
+77 −0
Original line number Diff line number Diff line
@@ -32,6 +32,11 @@ module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
		 " 0 - use default; < 0 - don't auto-establish");

u8 led_id = WIL_LED_INVALID_ID;
module_param(led_id, byte, S_IRUGO);
MODULE_PARM_DESC(led_id,
		 " 60G device led enablement. Set the led ID (0-2) to enable");

/**
 * WMI event receiving - theory of operations
 *
@@ -94,6 +99,14 @@ const struct fw_map fw_mapping[] = {
	 */
};

struct blink_on_off_time led_blink_time[] = {
	{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
	{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
	{WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
};

u8 led_polarity = LED_POLARITY_LOW_ACTIVE;

/**
 * return AHB address for given firmware/ucode internal (linker) address
 * @x - internal address
@@ -971,6 +984,60 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
	return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
}

int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
{
	int rc = 0;
	struct wmi_led_cfg_cmd cmd = {
		.led_mode = enable,
		.id = led_id,
		.slow_blink_cfg.blink_on =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
		.slow_blink_cfg.blink_off =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
		.medium_blink_cfg.blink_on =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
		.medium_blink_cfg.blink_off =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
		.fast_blink_cfg.blink_on =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
		.fast_blink_cfg.blink_off =
			cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
		.led_polarity = led_polarity,
	};
	struct {
		struct wmi_cmd_hdr wmi;
		struct wmi_led_cfg_done_event evt;
	} __packed reply;

	if (led_id == WIL_LED_INVALID_ID)
		goto out;

	if (led_id > WIL_LED_MAX_ID) {
		wil_err(wil, "Invalid led id %d\n", led_id);
		rc = -EINVAL;
		goto out;
	}

	wil_dbg_wmi(wil,
		    "%s led %d\n",
		    enable ? "enabling" : "disabling", led_id);

	rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
		      WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
		      100);
	if (rc)
		goto out;

	if (reply.evt.status) {
		wil_err(wil, "led %d cfg failed with status %d\n",
			led_id, le32_to_cpu(reply.evt.status));
		rc = -EINVAL;
	}

out:
	return rc;
}

int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
		  u8 chan, u8 hidden_ssid, u8 is_go)
{
@@ -1013,11 +1080,21 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
	if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
		rc = -EINVAL;

	if (wmi_nettype != WMI_NETTYPE_P2P)
		/* Don't fail due to error in the led configuration */
		wmi_led_cfg(wil, true);

	return rc;
}

int wmi_pcp_stop(struct wil6210_priv *wil)
{
	int rc;

	rc = wmi_led_cfg(wil, false);
	if (rc)
		return rc;

	return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
			WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
}
+61 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ enum wmi_command_id {
	WMI_THERMAL_THROTTLING_GET_STATUS_CMDID	= 0x855,
	WMI_OTP_READ_CMDID			= 0x856,
	WMI_OTP_WRITE_CMDID			= 0x857,
	WMI_LED_CFG_CMDID			= 0x858,
	/* Performance monitoring commands */
	WMI_BF_CTRL_CMDID			= 0x862,
	WMI_NOTIFY_REQ_CMDID			= 0x863,
@@ -868,6 +869,7 @@ enum wmi_event_id {
	WMI_RX_MGMT_PACKET_EVENTID		= 0x1840,
	WMI_TX_MGMT_PACKET_EVENTID		= 0x1841,
	WMI_OTP_READ_RESULT_EVENTID		= 0x1856,
	WMI_LED_CFG_DONE_EVENTID		= 0x1858,
	/* Performance monitoring events */
	WMI_DATA_PORT_OPEN_EVENTID		= 0x1860,
	WMI_WBE_LINK_DOWN_EVENTID		= 0x1861,
@@ -1349,4 +1351,63 @@ enum wmi_hidden_ssid {
	WMI_HIDDEN_SSID_CLEAR		= 0xFE,
};

/* WMI_LED_CFG_CMDID
 *
 * Configure LED On\Off\Blinking operation
 *
 * Returned events:
 * - WMI_LED_CFG_DONE_EVENTID
 */
enum led_mode {
	LED_DISABLE	= 0x00,
	LED_ENABLE	= 0x01,
};

/* The names of the led as
 * described on HW schemes.
 */
enum wmi_led_id {
	WMI_LED_WLAN	= 0x00,
	WMI_LED_WPAN	= 0x01,
	WMI_LED_WWAN	= 0x02,
};

/* Led polarity mode. */
enum wmi_led_polarity {
	LED_POLARITY_HIGH_ACTIVE	= 0x00,
	LED_POLARITY_LOW_ACTIVE		= 0x01,
};

/* Combination of on and off
 * creates the blinking period
 */
struct wmi_led_blink_mode {
	__le32 blink_on;
	__le32 blink_off;
} __packed;

/* WMI_LED_CFG_CMDID */
struct wmi_led_cfg_cmd {
	/* enum led_mode_e */
	u8 led_mode;
	/* enum wmi_led_id_e */
	u8 id;
	/* slow speed blinking combination */
	struct wmi_led_blink_mode slow_blink_cfg;
	/* medium speed blinking combination */
	struct wmi_led_blink_mode medium_blink_cfg;
	/* high speed blinking combination */
	struct wmi_led_blink_mode fast_blink_cfg;
	/* polarity of the led */
	u8 led_polarity;
	/* reserved */
	u8 reserved;
} __packed;

/* WMI_LED_CFG_DONE_EVENTID */
struct wmi_led_cfg_done_event {
	/* led config status */
	__le32 status;
} __packed;

#endif /* __WILOCITY_WMI_H__ */