12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
233cab57aSLuciano Coelho /*
333cab57aSLuciano Coelho * This file is part of wlcore
433cab57aSLuciano Coelho *
533cab57aSLuciano Coelho * Copyright (C) 2013 Texas Instruments Inc.
633cab57aSLuciano Coelho */
733cab57aSLuciano Coelho
8fa2648a3STony Lindgren #include <linux/pm_runtime.h>
9fa2648a3STony Lindgren
10fa2648a3STony Lindgren #include "acx.h"
1133cab57aSLuciano Coelho #include "wlcore.h"
1233cab57aSLuciano Coelho #include "debug.h"
1333cab57aSLuciano Coelho #include "sysfs.h"
1433cab57aSLuciano Coelho
bt_coex_state_show(struct device * dev,struct device_attribute * attr,char * buf)1586f1ea9dSYueHaibing static ssize_t bt_coex_state_show(struct device *dev,
1633cab57aSLuciano Coelho struct device_attribute *attr,
1733cab57aSLuciano Coelho char *buf)
1833cab57aSLuciano Coelho {
1933cab57aSLuciano Coelho struct wl1271 *wl = dev_get_drvdata(dev);
2033cab57aSLuciano Coelho ssize_t len;
2133cab57aSLuciano Coelho
2233cab57aSLuciano Coelho len = PAGE_SIZE;
2333cab57aSLuciano Coelho
2433cab57aSLuciano Coelho mutex_lock(&wl->mutex);
2533cab57aSLuciano Coelho len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2633cab57aSLuciano Coelho wl->sg_enabled);
2733cab57aSLuciano Coelho mutex_unlock(&wl->mutex);
2833cab57aSLuciano Coelho
2933cab57aSLuciano Coelho return len;
3033cab57aSLuciano Coelho
3133cab57aSLuciano Coelho }
3233cab57aSLuciano Coelho
bt_coex_state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3386f1ea9dSYueHaibing static ssize_t bt_coex_state_store(struct device *dev,
3433cab57aSLuciano Coelho struct device_attribute *attr,
3533cab57aSLuciano Coelho const char *buf, size_t count)
3633cab57aSLuciano Coelho {
3733cab57aSLuciano Coelho struct wl1271 *wl = dev_get_drvdata(dev);
3833cab57aSLuciano Coelho unsigned long res;
3933cab57aSLuciano Coelho int ret;
4033cab57aSLuciano Coelho
4133cab57aSLuciano Coelho ret = kstrtoul(buf, 10, &res);
4233cab57aSLuciano Coelho if (ret < 0) {
4333cab57aSLuciano Coelho wl1271_warning("incorrect value written to bt_coex_mode");
4433cab57aSLuciano Coelho return count;
4533cab57aSLuciano Coelho }
4633cab57aSLuciano Coelho
4733cab57aSLuciano Coelho mutex_lock(&wl->mutex);
4833cab57aSLuciano Coelho
4933cab57aSLuciano Coelho res = !!res;
5033cab57aSLuciano Coelho
5133cab57aSLuciano Coelho if (res == wl->sg_enabled)
5233cab57aSLuciano Coelho goto out;
5333cab57aSLuciano Coelho
5433cab57aSLuciano Coelho wl->sg_enabled = res;
5533cab57aSLuciano Coelho
5633cab57aSLuciano Coelho if (unlikely(wl->state != WLCORE_STATE_ON))
5733cab57aSLuciano Coelho goto out;
5833cab57aSLuciano Coelho
59*da8e909cSMinghao Chi ret = pm_runtime_resume_and_get(wl->dev);
60*da8e909cSMinghao Chi if (ret < 0)
6133cab57aSLuciano Coelho goto out;
6233cab57aSLuciano Coelho
6333cab57aSLuciano Coelho wl1271_acx_sg_enable(wl, wl->sg_enabled);
649b71578dSTony Lindgren pm_runtime_mark_last_busy(wl->dev);
659b71578dSTony Lindgren pm_runtime_put_autosuspend(wl->dev);
6633cab57aSLuciano Coelho
6733cab57aSLuciano Coelho out:
6833cab57aSLuciano Coelho mutex_unlock(&wl->mutex);
6933cab57aSLuciano Coelho return count;
7033cab57aSLuciano Coelho }
7133cab57aSLuciano Coelho
7286f1ea9dSYueHaibing static DEVICE_ATTR_RW(bt_coex_state);
7333cab57aSLuciano Coelho
hw_pg_ver_show(struct device * dev,struct device_attribute * attr,char * buf)7486f1ea9dSYueHaibing static ssize_t hw_pg_ver_show(struct device *dev,
7533cab57aSLuciano Coelho struct device_attribute *attr,
7633cab57aSLuciano Coelho char *buf)
7733cab57aSLuciano Coelho {
7833cab57aSLuciano Coelho struct wl1271 *wl = dev_get_drvdata(dev);
7933cab57aSLuciano Coelho ssize_t len;
8033cab57aSLuciano Coelho
8133cab57aSLuciano Coelho len = PAGE_SIZE;
8233cab57aSLuciano Coelho
8333cab57aSLuciano Coelho mutex_lock(&wl->mutex);
8433cab57aSLuciano Coelho if (wl->hw_pg_ver >= 0)
8533cab57aSLuciano Coelho len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
8633cab57aSLuciano Coelho else
8733cab57aSLuciano Coelho len = snprintf(buf, len, "n/a\n");
8833cab57aSLuciano Coelho mutex_unlock(&wl->mutex);
8933cab57aSLuciano Coelho
9033cab57aSLuciano Coelho return len;
9133cab57aSLuciano Coelho }
9233cab57aSLuciano Coelho
9386f1ea9dSYueHaibing static DEVICE_ATTR_RO(hw_pg_ver);
9433cab57aSLuciano Coelho
wl1271_sysfs_read_fwlog(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buffer,loff_t pos,size_t count)9533cab57aSLuciano Coelho static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
9633cab57aSLuciano Coelho struct bin_attribute *bin_attr,
9733cab57aSLuciano Coelho char *buffer, loff_t pos, size_t count)
9833cab57aSLuciano Coelho {
993b52cf62STian Tao struct device *dev = kobj_to_dev(kobj);
10033cab57aSLuciano Coelho struct wl1271 *wl = dev_get_drvdata(dev);
10133cab57aSLuciano Coelho ssize_t len;
10233cab57aSLuciano Coelho int ret;
10333cab57aSLuciano Coelho
10433cab57aSLuciano Coelho ret = mutex_lock_interruptible(&wl->mutex);
10533cab57aSLuciano Coelho if (ret < 0)
10633cab57aSLuciano Coelho return -ERESTARTSYS;
10733cab57aSLuciano Coelho
10833cab57aSLuciano Coelho /* Check if the fwlog is still valid */
10933cab57aSLuciano Coelho if (wl->fwlog_size < 0) {
11033cab57aSLuciano Coelho mutex_unlock(&wl->mutex);
11133cab57aSLuciano Coelho return 0;
11233cab57aSLuciano Coelho }
11333cab57aSLuciano Coelho
11433cab57aSLuciano Coelho /* Seeking is not supported - old logs are not kept. Disregard pos. */
115c8e49556SSilvan Jegen len = min_t(size_t, count, wl->fwlog_size);
11633cab57aSLuciano Coelho wl->fwlog_size -= len;
11733cab57aSLuciano Coelho memcpy(buffer, wl->fwlog, len);
11833cab57aSLuciano Coelho
11933cab57aSLuciano Coelho /* Make room for new messages */
12033cab57aSLuciano Coelho memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
12133cab57aSLuciano Coelho
12233cab57aSLuciano Coelho mutex_unlock(&wl->mutex);
12333cab57aSLuciano Coelho
12433cab57aSLuciano Coelho return len;
12533cab57aSLuciano Coelho }
12633cab57aSLuciano Coelho
1274f2949feSBhumika Goyal static const struct bin_attribute fwlog_attr = {
1282ef00c53SJoe Perches .attr = { .name = "fwlog", .mode = 0400 },
12933cab57aSLuciano Coelho .read = wl1271_sysfs_read_fwlog,
13033cab57aSLuciano Coelho };
13133cab57aSLuciano Coelho
wlcore_sysfs_init(struct wl1271 * wl)13233cab57aSLuciano Coelho int wlcore_sysfs_init(struct wl1271 *wl)
13333cab57aSLuciano Coelho {
13433cab57aSLuciano Coelho int ret;
13533cab57aSLuciano Coelho
13633cab57aSLuciano Coelho /* Create sysfs file to control bt coex state */
13733cab57aSLuciano Coelho ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
13833cab57aSLuciano Coelho if (ret < 0) {
13933cab57aSLuciano Coelho wl1271_error("failed to create sysfs file bt_coex_state");
14033cab57aSLuciano Coelho goto out;
14133cab57aSLuciano Coelho }
14233cab57aSLuciano Coelho
14333cab57aSLuciano Coelho /* Create sysfs file to get HW PG version */
14433cab57aSLuciano Coelho ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
14533cab57aSLuciano Coelho if (ret < 0) {
14633cab57aSLuciano Coelho wl1271_error("failed to create sysfs file hw_pg_ver");
14733cab57aSLuciano Coelho goto out_bt_coex_state;
14833cab57aSLuciano Coelho }
14933cab57aSLuciano Coelho
15033cab57aSLuciano Coelho /* Create sysfs file for the FW log */
15133cab57aSLuciano Coelho ret = device_create_bin_file(wl->dev, &fwlog_attr);
15233cab57aSLuciano Coelho if (ret < 0) {
15333cab57aSLuciano Coelho wl1271_error("failed to create sysfs file fwlog");
15433cab57aSLuciano Coelho goto out_hw_pg_ver;
15533cab57aSLuciano Coelho }
15633cab57aSLuciano Coelho
15733cab57aSLuciano Coelho goto out;
15833cab57aSLuciano Coelho
15933cab57aSLuciano Coelho out_hw_pg_ver:
16033cab57aSLuciano Coelho device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
16133cab57aSLuciano Coelho
16233cab57aSLuciano Coelho out_bt_coex_state:
16333cab57aSLuciano Coelho device_remove_file(wl->dev, &dev_attr_bt_coex_state);
16433cab57aSLuciano Coelho
16533cab57aSLuciano Coelho out:
16633cab57aSLuciano Coelho return ret;
16733cab57aSLuciano Coelho }
16833cab57aSLuciano Coelho
wlcore_sysfs_free(struct wl1271 * wl)16933cab57aSLuciano Coelho void wlcore_sysfs_free(struct wl1271 *wl)
17033cab57aSLuciano Coelho {
17133cab57aSLuciano Coelho device_remove_bin_file(wl->dev, &fwlog_attr);
17233cab57aSLuciano Coelho
17333cab57aSLuciano Coelho device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
17433cab57aSLuciano Coelho
17533cab57aSLuciano Coelho device_remove_file(wl->dev, &dev_attr_bt_coex_state);
17633cab57aSLuciano Coelho }
177