730 lines
18 KiB
C
Executable File
730 lines
18 KiB
C
Executable File
/*
|
|
* tfa_log.c tfa98xx logging in sysfs
|
|
*
|
|
* Copyright (c) 2015 NXP Semiconductors
|
|
*
|
|
* Author: Michael Kim <michael.kim@nxp.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/string.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/sysfs.h>
|
|
|
|
#include "tfa98xx_tfafieldnames.h"
|
|
#include "tfa_internal.h"
|
|
#include "tfa_service.h"
|
|
#include "tfa_container.h"
|
|
#include "tfa98xx_genregs_N1C.h"
|
|
|
|
#define TFA_CLASS_NAME "nxp"
|
|
#define TFA_LOG_DEV_NAME "tfa_log"
|
|
#define TFA_LOG_MAX_COUNT 4
|
|
#define DESC_MAXX_LOG "maxium of X"
|
|
#define DESC_MAXT_LOG "maximum of T"
|
|
#define DESC_OVERXMAX_COUNT "counter of X > Xmax"
|
|
#define DESC_OVERTMAX_COUNT "counter of T > Tmax"
|
|
#define TFA_LOG_IN_SEPARATE_NODES
|
|
#if defined(TFA_LOG_IN_SEPARATE_NODES)
|
|
#define FILESIZE_LOG 10
|
|
#else
|
|
#define FILESIZE_LOG (10 * TFA_LOG_MAX_COUNT)
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#if defined(TFA_LOG_IN_SEPARATE_NODES)
|
|
static ssize_t tfa_data_maxx_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_data_maxx_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(data_maxx, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_data_maxx_show, tfa_data_maxx_store);
|
|
|
|
static ssize_t tfa_data_maxt_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_data_maxt_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(data_maxt, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_data_maxt_show, tfa_data_maxt_store);
|
|
|
|
static ssize_t tfa_count_overxmax_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_count_overxmax_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(count_overxmax, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_count_overxmax_show, tfa_count_overxmax_store);
|
|
|
|
static ssize_t tfa_count_overtmax_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_count_overtmax_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(count_overtmax, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_count_overtmax_show, tfa_count_overtmax_store);
|
|
#else
|
|
static ssize_t tfa_data_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_data_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(data, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_data_show, tfa_data_store);
|
|
#endif
|
|
|
|
static ssize_t tfa_log_enable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_log_enable_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_log_enable_show, tfa_log_enable_store);
|
|
|
|
/*
|
|
* to check the data in debug log, in the middle by force
|
|
* without hurting scheme to reset after reading
|
|
*/
|
|
static ssize_t tfa_log_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
static ssize_t tfa_log_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size);
|
|
static DEVICE_ATTR(log, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
tfa_log_show, tfa_log_store);
|
|
|
|
static struct attribute *tfa_log_attr[] = {
|
|
#if defined(TFA_LOG_IN_SEPARATE_NODES)
|
|
&dev_attr_data_maxx.attr,
|
|
&dev_attr_data_maxt.attr,
|
|
&dev_attr_count_overxmax.attr,
|
|
&dev_attr_count_overtmax.attr,
|
|
#else
|
|
&dev_attr_data.attr,
|
|
#endif
|
|
&dev_attr_enable.attr,
|
|
&dev_attr_log.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group tfa_log_attr_grp = {
|
|
.attrs = tfa_log_attr,
|
|
};
|
|
|
|
struct tfa_log {
|
|
char *desc;
|
|
uint16_t prev_value;
|
|
bool is_max;
|
|
bool is_counter;
|
|
bool is_dirty;
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
extern struct class *g_nxp_class;
|
|
struct device *g_tfa_log_dev;
|
|
static int cur_status;
|
|
static struct tfa_log blackbox[TFA_LOG_MAX_COUNT];
|
|
static bool blackbox_enabled;
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* temporarily until API is ready for driver */
|
|
static enum tfa98xx_error
|
|
tfa_read_log(tfa98xx_handle_t handle,
|
|
uint16_t index, uint16_t *value, bool reset);
|
|
|
|
static enum tfa98xx_error
|
|
tfa_read_log(tfa98xx_handle_t handle,
|
|
uint16_t index, uint16_t *value, bool reset)
|
|
{
|
|
pr_info("%s [%d]: %s\n", __func__, index, blackbox[index].desc);
|
|
|
|
if (blackbox[index].is_dirty) {
|
|
pr_info("%s: it's read before updated\n", __func__);
|
|
*value = 0; /* no meaningful data to be updated */
|
|
return TFA98XX_ERROR_OK;
|
|
}
|
|
|
|
*value = blackbox[index].prev_value;
|
|
if (*value == 0xffff) {
|
|
pr_info("%s: invalid data\n", __func__);
|
|
return TFA98XX_ERROR_BAD_PARAMETER;
|
|
}
|
|
|
|
if (reset) {
|
|
/* reset the last data */
|
|
blackbox[index].prev_value = 0;
|
|
blackbox[index].is_dirty = 1;
|
|
}
|
|
|
|
return TFA98XX_ERROR_OK;
|
|
}
|
|
|
|
static int tfa_configure_log(void)
|
|
{
|
|
int idx, devcount = tfa98xx_cnt_max_device();
|
|
enum tfa98xx_error err;
|
|
int is_handle_open = 0;
|
|
uint8_t cmd_buf[3];
|
|
|
|
cmd_buf[0] = 0;
|
|
cmd_buf[1] = 0;
|
|
/* 0 - disable logger, 1 - enable logger */
|
|
cmd_buf[2] = (blackbox_enabled) ? 1 : 0;
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
pr_info("%s: set blackbox (%d)\n",
|
|
__func__, blackbox_enabled);
|
|
is_handle_open = tfa98xx_handle_is_open(idx);
|
|
if (!is_handle_open) {
|
|
err = tfa98xx_open(idx);
|
|
if (err) {
|
|
pr_info("cannot open handle (%d)\n", err);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
err = tfa_dsp_cmd_id_write
|
|
(idx, MODULE_SPEAKERBOOST,
|
|
SB_PARAM_SET_DATA_LOGGER, 3, cmd_buf);
|
|
if (err)
|
|
pr_err("%s: error in setting blackbox, err = %d\n",
|
|
__func__, err);
|
|
|
|
if (!is_handle_open)
|
|
tfa98xx_close(idx);
|
|
}
|
|
|
|
return TFA98XX_ERROR_OK;
|
|
}
|
|
|
|
static int tfa_update_log(void)
|
|
{
|
|
int i, idx, devcount = tfa98xx_cnt_max_device();
|
|
enum tfa98xx_error err;
|
|
int is_handle_open = 0;
|
|
uint8_t cmd_buf[(TFA_LOG_MAX_COUNT + 1) * TFACONT_MAXDEVS * 3];
|
|
int data[(TFA_LOG_MAX_COUNT + 1) * TFACONT_MAXDEVS];
|
|
int read_size;
|
|
|
|
if (!blackbox_enabled) {
|
|
pr_info("%s: blackbox is inactive\n", __func__);
|
|
return TFA98XX_ERROR_OK;
|
|
}
|
|
|
|
read_size = (TFA_LOG_MAX_COUNT + 1) * devcount * 3;
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
pr_info("%s: read from blackbox\n", __func__);
|
|
is_handle_open = tfa98xx_handle_is_open(idx);
|
|
if (!is_handle_open) {
|
|
err = tfa98xx_open(idx);
|
|
if (err) {
|
|
pr_info("cannot open handle (%d)\n", err);
|
|
return err;
|
|
}
|
|
}
|
|
|
|
err = tfa_dsp_cmd_id_write_read
|
|
(idx, MODULE_SPEAKERBOOST,
|
|
SB_PARAM_GET_DATA_LOGGER,
|
|
read_size, cmd_buf);
|
|
if (err) {
|
|
pr_err("%s: failed to read data from blackbox, err = %d\n",
|
|
__func__, err);
|
|
return err;
|
|
}
|
|
|
|
|
|
tfa98xx_convert_bytes2data(read_size, cmd_buf, data);
|
|
|
|
/* maximum x */
|
|
data[1] = (int)(data[1] / (TFA2_FW_X_DATA_SCALE / 1000));
|
|
/* maximum t */
|
|
data[2] = (int)(data[2] / TFA2_FW_T_DATA_SCALE);
|
|
for (i = 0; i < TFA_LOG_MAX_COUNT; i++)
|
|
pr_info("blackbox: data[%d] = %d\n", i, data[i + 1]);
|
|
|
|
if (!is_handle_open)
|
|
tfa98xx_close(idx);
|
|
}
|
|
|
|
for (i = 0; i < TFA_LOG_MAX_COUNT; i++) {
|
|
blackbox[i].is_dirty = 0;
|
|
|
|
if (blackbox[i].is_max)
|
|
blackbox[i].prev_value =
|
|
(data[i + 1] > blackbox[i].prev_value)
|
|
? data[i + 1] : blackbox[i].prev_value;
|
|
if (blackbox[i].is_counter)
|
|
blackbox[i].prev_value += data[i + 1];
|
|
}
|
|
|
|
return TFA98XX_ERROR_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
#if defined(TFA_LOG_IN_SEPARATE_NODES)
|
|
static ssize_t tfa_data_maxx_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value = 0xffff;
|
|
int size;
|
|
int ret = 0;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[0].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret = tfa_read_log(idx, 0, &value, true);
|
|
if (ret) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d", value);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, value);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
|
|
if (ret)
|
|
size = snprintf(buf, FILESIZE_LOG, "data error");
|
|
else
|
|
size = snprintf(buf,
|
|
FILESIZE_LOG, "%s", read_string);
|
|
|
|
if (size <= 0) {
|
|
pr_err("%s: failed to show in sysfs file", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_data_maxx_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
pr_info("%s: not allowed to write log data: %s\n",
|
|
__func__, blackbox[0].desc);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_data_maxt_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value = 0xffff;
|
|
int size;
|
|
int ret = 0;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[1].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret = tfa_read_log(idx, 1, &value, true);
|
|
if (ret) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d", value);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, value);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
|
|
if (ret)
|
|
size = snprintf(buf, FILESIZE_LOG, "data error");
|
|
else
|
|
size = snprintf(buf,
|
|
FILESIZE_LOG, "%s", read_string);
|
|
|
|
if (size <= 0) {
|
|
pr_err("%s: failed to show in sysfs file", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_data_maxt_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
pr_info("%s: not allowed to write log data: %s\n",
|
|
__func__, blackbox[1].desc);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_count_overxmax_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value = 0xffff;
|
|
int size;
|
|
int ret = 0;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[2].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret = tfa_read_log(idx, 2, &value, true);
|
|
if (ret) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d", value);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, value);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
|
|
if (ret)
|
|
size = snprintf(buf, FILESIZE_LOG, "data error");
|
|
else
|
|
size = snprintf(buf,
|
|
FILESIZE_LOG, "%s", read_string);
|
|
|
|
if (size <= 0) {
|
|
pr_err("%s: failed to show in sysfs file", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_count_overxmax_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
pr_info("%s: not allowed to write log data: %s\n",
|
|
__func__, blackbox[2].desc);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_count_overtmax_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value = 0xffff;
|
|
int size;
|
|
int ret = 0;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[3].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret = tfa_read_log(idx, 3, &value, true);
|
|
if (ret) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d", value);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, value);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
|
|
if (ret)
|
|
size = snprintf(buf, FILESIZE_LOG, "data error");
|
|
else
|
|
size = snprintf(buf,
|
|
FILESIZE_LOG, "%s", read_string);
|
|
|
|
if (size <= 0) {
|
|
pr_err("%s: failed to show in sysfs file", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_count_overtmax_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
pr_info("%s: not allowed to write log data: %s\n",
|
|
__func__, blackbox[3].desc);
|
|
|
|
return size;
|
|
}
|
|
#else /* TFA_LOG_IN_SEPARATE_NODES */
|
|
static ssize_t tfa_data_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int i, idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value[TFA_LOG_MAX_COUNT] = {0xffff};
|
|
int size;
|
|
int ret = 0;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
for (i = 0; i < TFA_LOG_MAX_COUNT; i++) {
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[i].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret = tfa_read_log(idx, i, &value[i], true);
|
|
if (ret) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d", value[i]);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, value[i]);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
}
|
|
|
|
if (ret)
|
|
size = snprintf(buf, FILESIZE_LOG, "data error");
|
|
else
|
|
size = snprintf(buf,
|
|
FILESIZE_LOG, "%s", read_string);
|
|
|
|
if (size <= 0) {
|
|
pr_err("%s: failed to show in sysfs file", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret);
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_data_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
pr_info("%s: not allowed to write log data\n",
|
|
__func__);
|
|
|
|
return size;
|
|
}
|
|
#endif /* TFA_LOG_IN_SEPARATE_NODES */
|
|
|
|
static ssize_t tfa_log_enable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int size;
|
|
|
|
size = snprintf(buf, 25, "%s\n", blackbox_enabled ?
|
|
"blackbox is active" : "blackbox is inactive");
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_log_enable_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
int ret = 0;
|
|
int status;
|
|
|
|
/* Compare string, excluding the trailing \0 and the potentials eol */
|
|
if (!sysfs_streq(buf, "1") && !sysfs_streq(buf, "0")) {
|
|
pr_debug("%s: invalid value to write\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = kstrtou32(buf, 10, &status);
|
|
blackbox_enabled = (status) ? true : false;
|
|
|
|
tfa_configure_log();
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_log_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int size;
|
|
|
|
size = snprintf(buf, 25, "%s\n", cur_status ?
|
|
"sysfs log is active" : "sysfs log is inactive");
|
|
|
|
return size;
|
|
}
|
|
|
|
static ssize_t tfa_log_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t size)
|
|
{
|
|
int i, idx, devcount = tfa98xx_cnt_max_device();
|
|
uint16_t value[TFA_LOG_MAX_COUNT] = {0xffff};
|
|
int ret = 0, ret2 = 0;
|
|
int status;
|
|
char read_string[FILESIZE_LOG] = {0};
|
|
|
|
/* Compare string, excluding the trailing \0 and the potentials eol */
|
|
if (!sysfs_streq(buf, "1") && !sysfs_streq(buf, "0")) {
|
|
pr_debug("%s: invalid value to write\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = kstrtou32(buf, 10, &status);
|
|
if (!status) {
|
|
pr_info("%s: do nothing\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (cur_status)
|
|
pr_info("%s: prior writing still runs\n", __func__);
|
|
|
|
pr_info("%s: begin\n", __func__);
|
|
|
|
cur_status = status; /* run - changed to active */
|
|
for (i = 0; i < TFA_LOG_MAX_COUNT; i++) {
|
|
pr_info("%s: read from driver: %s\n",
|
|
__func__, blackbox[i].desc);
|
|
|
|
for (idx = 0; idx < devcount; idx++) {
|
|
/* reset the data in driver after reading */
|
|
ret2 = tfa_read_log(idx, i, &value[i], false);
|
|
if (ret2) {
|
|
pr_info("%s: failed to read data from driver\n",
|
|
__func__);
|
|
continue;
|
|
}
|
|
|
|
cur_status = 0; /* done - changed to inactive */
|
|
|
|
if (idx == 0)
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%d",
|
|
blackbox[i].prev_value);
|
|
else
|
|
snprintf(read_string,
|
|
FILESIZE_LOG, "%s %d",
|
|
read_string, blackbox[i].prev_value);
|
|
}
|
|
|
|
pr_info("%s: %s\n", __func__, read_string);
|
|
}
|
|
|
|
pr_info("%s: end (%d)\n", __func__, ret2);
|
|
|
|
return size;
|
|
}
|
|
|
|
static int __init tfa98xx_log_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!g_nxp_class)
|
|
g_nxp_class = class_create(THIS_MODULE, TFA_CLASS_NAME);
|
|
if (g_nxp_class) {
|
|
g_tfa_log_dev = device_create(g_nxp_class,
|
|
NULL, 2, NULL, TFA_LOG_DEV_NAME);
|
|
if (!IS_ERR(g_tfa_log_dev)) {
|
|
ret = sysfs_create_group(&g_tfa_log_dev->kobj,
|
|
&tfa_log_attr_grp);
|
|
if (ret)
|
|
pr_err("%s: failed to create sysfs group. ret (%d)\n",
|
|
__func__, ret);
|
|
} else {
|
|
class_destroy(g_nxp_class);
|
|
}
|
|
}
|
|
|
|
#if defined(TFA_BLACKBOX_LOGGING)
|
|
blackbox_enabled = true; /* enable by default */
|
|
#else
|
|
blackbox_enabled = false; /* control with sysfs node */
|
|
#endif
|
|
|
|
tfa_log_register(tfa_configure_log, tfa_update_log);
|
|
|
|
/* maximum x */
|
|
blackbox[0].desc = DESC_MAXX_LOG;
|
|
blackbox[0].is_max = true;
|
|
blackbox[0].is_counter = false;
|
|
/* maximum t */
|
|
blackbox[1].desc = DESC_MAXT_LOG;
|
|
blackbox[1].is_max = true;
|
|
blackbox[1].is_counter = false;
|
|
/* counter x > x_max */
|
|
blackbox[2].desc = DESC_OVERXMAX_COUNT;
|
|
blackbox[2].is_max = false;
|
|
blackbox[2].is_counter = true;
|
|
/* counter t > t_max */
|
|
blackbox[3].desc = DESC_OVERTMAX_COUNT;
|
|
blackbox[3].is_max = false;
|
|
blackbox[3].is_counter = true;
|
|
|
|
pr_info("%s: g_nxp_class=%p\n", __func__, g_nxp_class);
|
|
pr_info("%s: initialized\n", __func__);
|
|
|
|
return ret;
|
|
}
|
|
module_init(tfa98xx_log_init);
|
|
|
|
static void __exit tfa98xx_log_exit(void)
|
|
{
|
|
device_destroy(g_nxp_class, 2);
|
|
class_destroy(g_nxp_class);
|
|
pr_info("exited\n");
|
|
}
|
|
module_exit(tfa98xx_log_exit);
|
|
|
|
MODULE_DESCRIPTION("ASoC TFA98XX logging driver");
|
|
MODULE_LICENSE("GPL");
|