Skip to content

Commit

Permalink
wil6210: add support for device led configuration
Browse files Browse the repository at this point in the history
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: Maya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
  • Loading branch information
Maya Erez authored and Kalle Valo committed May 11, 2016
1 parent 41842dc commit 10d599a
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 0 deletions.
115 changes: 115 additions & 0 deletions drivers/net/wireless/ath/wil6210/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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},
{},
};

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/wil6210/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions drivers/net/wireless/ath/wil6210/wil6210.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
77 changes: 77 additions & 0 deletions drivers/net/wireless/ath/wil6210/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
Expand Down
61 changes: 61 additions & 0 deletions drivers/net/wireless/ath/wil6210/wmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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__ */

0 comments on commit 10d599a

Please sign in to comment.