Linux Audio

Check our new training course

Loading...
v4.17
 
  1/*
  2 * This file is part of wlcore
  3 *
  4 * Copyright (C) 2013 Texas Instruments Inc.
  5 *
  6 * This program is free software; you can redistribute it and/or
  7 * modify it under the terms of the GNU General Public License
  8 * version 2 as published by the Free Software Foundation.
  9 *
 10 * This program is distributed in the hope that it will be useful, but
 11 * WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13 * General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU General Public License
 16 * along with this program; if not, write to the Free Software
 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 18 * 02110-1301 USA
 19 *
 20 */
 21
 
 
 
 22#include "wlcore.h"
 23#include "debug.h"
 24#include "ps.h"
 25#include "sysfs.h"
 26
 27static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
 28					       struct device_attribute *attr,
 29					       char *buf)
 30{
 31	struct wl1271 *wl = dev_get_drvdata(dev);
 32	ssize_t len;
 33
 34	len = PAGE_SIZE;
 35
 36	mutex_lock(&wl->mutex);
 37	len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
 38		       wl->sg_enabled);
 39	mutex_unlock(&wl->mutex);
 40
 41	return len;
 42
 43}
 44
 45static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
 46						struct device_attribute *attr,
 47						const char *buf, size_t count)
 48{
 49	struct wl1271 *wl = dev_get_drvdata(dev);
 50	unsigned long res;
 51	int ret;
 52
 53	ret = kstrtoul(buf, 10, &res);
 54	if (ret < 0) {
 55		wl1271_warning("incorrect value written to bt_coex_mode");
 56		return count;
 57	}
 58
 59	mutex_lock(&wl->mutex);
 60
 61	res = !!res;
 62
 63	if (res == wl->sg_enabled)
 64		goto out;
 65
 66	wl->sg_enabled = res;
 67
 68	if (unlikely(wl->state != WLCORE_STATE_ON))
 69		goto out;
 70
 71	ret = wl1271_ps_elp_wakeup(wl);
 72	if (ret < 0)
 73		goto out;
 74
 75	wl1271_acx_sg_enable(wl, wl->sg_enabled);
 76	wl1271_ps_elp_sleep(wl);
 
 77
 78 out:
 79	mutex_unlock(&wl->mutex);
 80	return count;
 81}
 82
 83static DEVICE_ATTR(bt_coex_state, 0644,
 84		   wl1271_sysfs_show_bt_coex_state,
 85		   wl1271_sysfs_store_bt_coex_state);
 86
 87static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
 88					   struct device_attribute *attr,
 89					   char *buf)
 90{
 91	struct wl1271 *wl = dev_get_drvdata(dev);
 92	ssize_t len;
 93
 94	len = PAGE_SIZE;
 95
 96	mutex_lock(&wl->mutex);
 97	if (wl->hw_pg_ver >= 0)
 98		len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
 99	else
100		len = snprintf(buf, len, "n/a\n");
101	mutex_unlock(&wl->mutex);
102
103	return len;
104}
105
106static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL);
107
108static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
109				       struct bin_attribute *bin_attr,
110				       char *buffer, loff_t pos, size_t count)
111{
112	struct device *dev = container_of(kobj, struct device, kobj);
113	struct wl1271 *wl = dev_get_drvdata(dev);
114	ssize_t len;
115	int ret;
116
117	ret = mutex_lock_interruptible(&wl->mutex);
118	if (ret < 0)
119		return -ERESTARTSYS;
120
121	/* Check if the fwlog is still valid */
122	if (wl->fwlog_size < 0) {
123		mutex_unlock(&wl->mutex);
124		return 0;
125	}
126
127	/* Seeking is not supported - old logs are not kept. Disregard pos. */
128	len = min_t(size_t, count, wl->fwlog_size);
129	wl->fwlog_size -= len;
130	memcpy(buffer, wl->fwlog, len);
131
132	/* Make room for new messages */
133	memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
134
135	mutex_unlock(&wl->mutex);
136
137	return len;
138}
139
140static const struct bin_attribute fwlog_attr = {
141	.attr = { .name = "fwlog", .mode = 0400 },
142	.read = wl1271_sysfs_read_fwlog,
143};
144
145int wlcore_sysfs_init(struct wl1271 *wl)
146{
147	int ret;
148
149	/* Create sysfs file to control bt coex state */
150	ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
151	if (ret < 0) {
152		wl1271_error("failed to create sysfs file bt_coex_state");
153		goto out;
154	}
155
156	/* Create sysfs file to get HW PG version */
157	ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
158	if (ret < 0) {
159		wl1271_error("failed to create sysfs file hw_pg_ver");
160		goto out_bt_coex_state;
161	}
162
163	/* Create sysfs file for the FW log */
164	ret = device_create_bin_file(wl->dev, &fwlog_attr);
165	if (ret < 0) {
166		wl1271_error("failed to create sysfs file fwlog");
167		goto out_hw_pg_ver;
168	}
169
170	goto out;
171
172out_hw_pg_ver:
173	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
174
175out_bt_coex_state:
176	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
177
178out:
179	return ret;
180}
181
182void wlcore_sysfs_free(struct wl1271 *wl)
183{
184	device_remove_bin_file(wl->dev, &fwlog_attr);
185
186	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
187
188	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
189}
v6.8
  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	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 bt_coex_state_store(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_resume_and_get(wl->dev);
 60	if (ret < 0)
 61		goto out;
 62
 63	wl1271_acx_sg_enable(wl, wl->sg_enabled);
 64	pm_runtime_mark_last_busy(wl->dev);
 65	pm_runtime_put_autosuspend(wl->dev);
 66
 67 out:
 68	mutex_unlock(&wl->mutex);
 69	return count;
 70}
 71
 72static DEVICE_ATTR_RW(bt_coex_state);
 73
 74static ssize_t hw_pg_ver_show(struct device *dev,
 75			      struct device_attribute *attr,
 76			      char *buf)
 
 
 77{
 78	struct wl1271 *wl = dev_get_drvdata(dev);
 79	ssize_t len;
 80
 81	len = PAGE_SIZE;
 82
 83	mutex_lock(&wl->mutex);
 84	if (wl->hw_pg_ver >= 0)
 85		len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
 86	else
 87		len = snprintf(buf, len, "n/a\n");
 88	mutex_unlock(&wl->mutex);
 89
 90	return len;
 91}
 92
 93static DEVICE_ATTR_RO(hw_pg_ver);
 94
 95static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
 96				       struct bin_attribute *bin_attr,
 97				       char *buffer, loff_t pos, size_t count)
 98{
 99	struct device *dev = kobj_to_dev(kobj);
100	struct wl1271 *wl = dev_get_drvdata(dev);
101	ssize_t len;
102	int ret;
103
104	ret = mutex_lock_interruptible(&wl->mutex);
105	if (ret < 0)
106		return -ERESTARTSYS;
107
108	/* Check if the fwlog is still valid */
109	if (wl->fwlog_size < 0) {
110		mutex_unlock(&wl->mutex);
111		return 0;
112	}
113
114	/* Seeking is not supported - old logs are not kept. Disregard pos. */
115	len = min_t(size_t, count, wl->fwlog_size);
116	wl->fwlog_size -= len;
117	memcpy(buffer, wl->fwlog, len);
118
119	/* Make room for new messages */
120	memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
121
122	mutex_unlock(&wl->mutex);
123
124	return len;
125}
126
127static const struct bin_attribute fwlog_attr = {
128	.attr = { .name = "fwlog", .mode = 0400 },
129	.read = wl1271_sysfs_read_fwlog,
130};
131
132int wlcore_sysfs_init(struct wl1271 *wl)
133{
134	int ret;
135
136	/* Create sysfs file to control bt coex state */
137	ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
138	if (ret < 0) {
139		wl1271_error("failed to create sysfs file bt_coex_state");
140		goto out;
141	}
142
143	/* Create sysfs file to get HW PG version */
144	ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
145	if (ret < 0) {
146		wl1271_error("failed to create sysfs file hw_pg_ver");
147		goto out_bt_coex_state;
148	}
149
150	/* Create sysfs file for the FW log */
151	ret = device_create_bin_file(wl->dev, &fwlog_attr);
152	if (ret < 0) {
153		wl1271_error("failed to create sysfs file fwlog");
154		goto out_hw_pg_ver;
155	}
156
157	goto out;
158
159out_hw_pg_ver:
160	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
161
162out_bt_coex_state:
163	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
164
165out:
166	return ret;
167}
168
169void wlcore_sysfs_free(struct wl1271 *wl)
170{
171	device_remove_bin_file(wl->dev, &fwlog_attr);
172
173	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
174
175	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
176}