Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * This file is part of wlcore
  4 *
  5 * Copyright (C) 2013 Texas Instruments Inc.
  6 */
  7
  8#include <linux/pm_runtime.h>
  9
 10#include "acx.h"
 11#include "wlcore.h"
 12#include "debug.h"
 13#include "sysfs.h"
 14
 15static ssize_t bt_coex_state_show(struct device *dev,
 16				  struct device_attribute *attr,
 17				  char *buf)
 18{
 19	struct wl1271 *wl = dev_get_drvdata(dev);
 20	ssize_t len;
 21
 
 
 22	mutex_lock(&wl->mutex);
 23	len = sysfs_emit(buf, "%d\n\n0 - off\n1 - on\n", wl->sg_enabled);
 
 24	mutex_unlock(&wl->mutex);
 25
 26	return len;
 27
 28}
 29
 30static ssize_t bt_coex_state_store(struct device *dev,
 31				   struct device_attribute *attr,
 32				   const char *buf, size_t count)
 33{
 34	struct wl1271 *wl = dev_get_drvdata(dev);
 35	unsigned long res;
 36	int ret;
 37
 38	ret = kstrtoul(buf, 10, &res);
 39	if (ret < 0) {
 40		wl1271_warning("incorrect value written to bt_coex_mode");
 41		return count;
 42	}
 43
 44	mutex_lock(&wl->mutex);
 45
 46	res = !!res;
 47
 48	if (res == wl->sg_enabled)
 49		goto out;
 50
 51	wl->sg_enabled = res;
 52
 53	if (unlikely(wl->state != WLCORE_STATE_ON))
 54		goto out;
 55
 56	ret = pm_runtime_resume_and_get(wl->dev);
 57	if (ret < 0)
 
 58		goto out;
 
 59
 60	wl1271_acx_sg_enable(wl, wl->sg_enabled);
 61	pm_runtime_mark_last_busy(wl->dev);
 62	pm_runtime_put_autosuspend(wl->dev);
 63
 64 out:
 65	mutex_unlock(&wl->mutex);
 66	return count;
 67}
 68
 69static DEVICE_ATTR_RW(bt_coex_state);
 70
 71static ssize_t hw_pg_ver_show(struct device *dev,
 72			      struct device_attribute *attr,
 73			      char *buf)
 
 
 74{
 75	struct wl1271 *wl = dev_get_drvdata(dev);
 76	ssize_t len;
 77
 
 
 78	mutex_lock(&wl->mutex);
 79	if (wl->hw_pg_ver >= 0)
 80		len = sysfs_emit(buf, "%d\n", wl->hw_pg_ver);
 81	else
 82		len = sysfs_emit(buf, "n/a\n");
 83	mutex_unlock(&wl->mutex);
 84
 85	return len;
 86}
 87
 88static DEVICE_ATTR_RO(hw_pg_ver);
 89
 90static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
 91				       struct bin_attribute *bin_attr,
 92				       char *buffer, loff_t pos, size_t count)
 93{
 94	struct device *dev = kobj_to_dev(kobj);
 95	struct wl1271 *wl = dev_get_drvdata(dev);
 96	ssize_t len;
 97	int ret;
 98
 99	ret = mutex_lock_interruptible(&wl->mutex);
100	if (ret < 0)
101		return -ERESTARTSYS;
102
103	/* Check if the fwlog is still valid */
104	if (wl->fwlog_size < 0) {
105		mutex_unlock(&wl->mutex);
106		return 0;
107	}
108
109	/* Seeking is not supported - old logs are not kept. Disregard pos. */
110	len = min_t(size_t, count, wl->fwlog_size);
111	wl->fwlog_size -= len;
112	memcpy(buffer, wl->fwlog, len);
113
114	/* Make room for new messages */
115	memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
116
117	mutex_unlock(&wl->mutex);
118
119	return len;
120}
121
122static const struct bin_attribute fwlog_attr = {
123	.attr = { .name = "fwlog", .mode = 0400 },
124	.read = wl1271_sysfs_read_fwlog,
125};
126
127int wlcore_sysfs_init(struct wl1271 *wl)
128{
129	int ret;
130
131	/* Create sysfs file to control bt coex state */
132	ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
133	if (ret < 0) {
134		wl1271_error("failed to create sysfs file bt_coex_state");
135		goto out;
136	}
137
138	/* Create sysfs file to get HW PG version */
139	ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
140	if (ret < 0) {
141		wl1271_error("failed to create sysfs file hw_pg_ver");
142		goto out_bt_coex_state;
143	}
144
145	/* Create sysfs file for the FW log */
146	ret = device_create_bin_file(wl->dev, &fwlog_attr);
147	if (ret < 0) {
148		wl1271_error("failed to create sysfs file fwlog");
149		goto out_hw_pg_ver;
150	}
151
152	goto out;
153
154out_hw_pg_ver:
155	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
156
157out_bt_coex_state:
158	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
159
160out:
161	return ret;
162}
163
164void wlcore_sysfs_free(struct wl1271 *wl)
165{
166	device_remove_bin_file(wl->dev, &fwlog_attr);
167
168	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
169
170	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
171}
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * This file is part of wlcore
  4 *
  5 * Copyright (C) 2013 Texas Instruments Inc.
  6 */
  7
  8#include <linux/pm_runtime.h>
  9
 10#include "acx.h"
 11#include "wlcore.h"
 12#include "debug.h"
 13#include "sysfs.h"
 14
 15static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
 16					       struct device_attribute *attr,
 17					       char *buf)
 18{
 19	struct wl1271 *wl = dev_get_drvdata(dev);
 20	ssize_t len;
 21
 22	len = PAGE_SIZE;
 23
 24	mutex_lock(&wl->mutex);
 25	len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
 26		       wl->sg_enabled);
 27	mutex_unlock(&wl->mutex);
 28
 29	return len;
 30
 31}
 32
 33static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
 34						struct device_attribute *attr,
 35						const char *buf, size_t count)
 36{
 37	struct wl1271 *wl = dev_get_drvdata(dev);
 38	unsigned long res;
 39	int ret;
 40
 41	ret = kstrtoul(buf, 10, &res);
 42	if (ret < 0) {
 43		wl1271_warning("incorrect value written to bt_coex_mode");
 44		return count;
 45	}
 46
 47	mutex_lock(&wl->mutex);
 48
 49	res = !!res;
 50
 51	if (res == wl->sg_enabled)
 52		goto out;
 53
 54	wl->sg_enabled = res;
 55
 56	if (unlikely(wl->state != WLCORE_STATE_ON))
 57		goto out;
 58
 59	ret = pm_runtime_get_sync(wl->dev);
 60	if (ret < 0) {
 61		pm_runtime_put_noidle(wl->dev);
 62		goto out;
 63	}
 64
 65	wl1271_acx_sg_enable(wl, wl->sg_enabled);
 66	pm_runtime_mark_last_busy(wl->dev);
 67	pm_runtime_put_autosuspend(wl->dev);
 68
 69 out:
 70	mutex_unlock(&wl->mutex);
 71	return count;
 72}
 73
 74static DEVICE_ATTR(bt_coex_state, 0644,
 75		   wl1271_sysfs_show_bt_coex_state,
 76		   wl1271_sysfs_store_bt_coex_state);
 77
 78static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
 79					   struct device_attribute *attr,
 80					   char *buf)
 81{
 82	struct wl1271 *wl = dev_get_drvdata(dev);
 83	ssize_t len;
 84
 85	len = PAGE_SIZE;
 86
 87	mutex_lock(&wl->mutex);
 88	if (wl->hw_pg_ver >= 0)
 89		len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
 90	else
 91		len = snprintf(buf, len, "n/a\n");
 92	mutex_unlock(&wl->mutex);
 93
 94	return len;
 95}
 96
 97static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL);
 98
 99static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
100				       struct bin_attribute *bin_attr,
101				       char *buffer, loff_t pos, size_t count)
102{
103	struct device *dev = container_of(kobj, struct device, kobj);
104	struct wl1271 *wl = dev_get_drvdata(dev);
105	ssize_t len;
106	int ret;
107
108	ret = mutex_lock_interruptible(&wl->mutex);
109	if (ret < 0)
110		return -ERESTARTSYS;
111
112	/* Check if the fwlog is still valid */
113	if (wl->fwlog_size < 0) {
114		mutex_unlock(&wl->mutex);
115		return 0;
116	}
117
118	/* Seeking is not supported - old logs are not kept. Disregard pos. */
119	len = min_t(size_t, count, wl->fwlog_size);
120	wl->fwlog_size -= len;
121	memcpy(buffer, wl->fwlog, len);
122
123	/* Make room for new messages */
124	memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
125
126	mutex_unlock(&wl->mutex);
127
128	return len;
129}
130
131static const struct bin_attribute fwlog_attr = {
132	.attr = { .name = "fwlog", .mode = 0400 },
133	.read = wl1271_sysfs_read_fwlog,
134};
135
136int wlcore_sysfs_init(struct wl1271 *wl)
137{
138	int ret;
139
140	/* Create sysfs file to control bt coex state */
141	ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
142	if (ret < 0) {
143		wl1271_error("failed to create sysfs file bt_coex_state");
144		goto out;
145	}
146
147	/* Create sysfs file to get HW PG version */
148	ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
149	if (ret < 0) {
150		wl1271_error("failed to create sysfs file hw_pg_ver");
151		goto out_bt_coex_state;
152	}
153
154	/* Create sysfs file for the FW log */
155	ret = device_create_bin_file(wl->dev, &fwlog_attr);
156	if (ret < 0) {
157		wl1271_error("failed to create sysfs file fwlog");
158		goto out_hw_pg_ver;
159	}
160
161	goto out;
162
163out_hw_pg_ver:
164	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
165
166out_bt_coex_state:
167	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
168
169out:
170	return ret;
171}
172
173void wlcore_sysfs_free(struct wl1271 *wl)
174{
175	device_remove_bin_file(wl->dev, &fwlog_attr);
176
177	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
178
179	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
180}