1155 lines
32 KiB
C
1155 lines
32 KiB
C
|
/* Copyright (c) 2015-2016, 2018, The Linux Foundation.
|
||
|
* All rights reserved.
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
* only version 2 as published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* Author : Vijeth (vijeth.po@pathpartnertech.com)
|
||
|
* Revised Date : 30-07-19
|
||
|
* Description : TI Smartamp algorithm control interface
|
||
|
*
|
||
|
*/
|
||
|
#ifdef CONFIG_TAS25XX_ALGO
|
||
|
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/version.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/kthread.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/wait.h>
|
||
|
#include <linux/jiffies.h>
|
||
|
#include <linux/sched.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/syscalls.h>
|
||
|
#include <linux/file.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/fs.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/of.h>
|
||
|
#include <sound/smart_amp.h>
|
||
|
#include <linux/power_supply.h>
|
||
|
#include "tas25xx-algo.h"
|
||
|
|
||
|
static uint32_t port;
|
||
|
|
||
|
static uint8_t calibration_result[MAX_CHANNELS] = {STATUS_NONE};
|
||
|
static uint8_t validation_result[MAX_CHANNELS] = {STATUS_NONE};
|
||
|
static bool calibration_status;
|
||
|
static bool validation_running_status;
|
||
|
static uint32_t calib_re_hold[MAX_CHANNELS] = {0};
|
||
|
static uint32_t amb_temp_hold[MAX_CHANNELS] = {0};
|
||
|
static int32_t g_iv_vbat_fmt = IV_SENSE_FORMAT_NO_VBAT;
|
||
|
static int32_t re_low[MAX_CHANNELS] = {0};
|
||
|
static int32_t re_high[MAX_CHANNELS] = {0};
|
||
|
|
||
|
/*Mutex to serialize DSP read/write commands*/
|
||
|
static struct mutex routing_lock;
|
||
|
static struct tas25xx_algo *p_tas25xx_algo;
|
||
|
|
||
|
/*Max value supported is 2^8*/
|
||
|
static uint8_t trans_val_to_user_m(uint32_t val, uint8_t qformat)
|
||
|
{
|
||
|
uint32_t ret = (uint32_t)(((long long)val * 1000) >> qformat) % 1000;
|
||
|
return (uint8_t)(ret / 10);
|
||
|
}
|
||
|
|
||
|
/*Max value supported is 2^8*/
|
||
|
static uint8_t trans_val_to_user_i(uint32_t val, uint8_t qformat)
|
||
|
{
|
||
|
return ((val * 100) >> qformat) / 100;
|
||
|
}
|
||
|
|
||
|
static int afe_smartamp_get_set(u8 *user_data, uint32_t param_id,
|
||
|
uint8_t get_set, uint32_t length)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct ti_smartpa_data resp_data;
|
||
|
|
||
|
if (!p_tas25xx_algo) {
|
||
|
pr_err("[TI-SmartPA:%s] memory not allocated yet for p_tas25xx_algo",
|
||
|
__func__);
|
||
|
}
|
||
|
|
||
|
switch (get_set) {
|
||
|
case TAS_SET_PARAM:
|
||
|
memcpy(resp_data.payload, user_data, length);
|
||
|
ret = ti_smartpa_write((void *)&resp_data,
|
||
|
param_id, length);
|
||
|
break;
|
||
|
case TAS_GET_PARAM:
|
||
|
memset(&resp_data, 0, sizeof(resp_data));
|
||
|
|
||
|
ret = ti_smartpa_read((void *)&resp_data,
|
||
|
param_id, length);
|
||
|
|
||
|
if (ret == 0)
|
||
|
memcpy(user_data, resp_data.payload, length);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
goto fail_cmd;
|
||
|
}
|
||
|
fail_cmd:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* Wrapper around set/get parameter, all set/get commands pass
|
||
|
* through this wrapper
|
||
|
*/
|
||
|
int afe_smartamp_algo_ctrl(u8 *user_data, uint32_t param_id,
|
||
|
uint8_t get_set, uint32_t length)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&routing_lock);
|
||
|
ret = afe_smartamp_get_set(user_data, param_id, get_set, length);
|
||
|
mutex_unlock(&routing_lock);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static uint8_t tas25xx_get_amb_temp(void)
|
||
|
{
|
||
|
struct power_supply *psy;
|
||
|
union power_supply_propval value = {0};
|
||
|
|
||
|
psy = power_supply_get_by_name("battery");
|
||
|
if (!psy || !psy->desc || !psy->desc->get_property) {
|
||
|
pr_err("[TI-SmartPA:%s] getting ambient temp failed, using default value %d",
|
||
|
__func__, DEFAULT_AMBIENT_TEMP);
|
||
|
return DEFAULT_AMBIENT_TEMP;
|
||
|
}
|
||
|
psy->desc->get_property(psy, POWER_SUPPLY_PROP_TEMP, &value);
|
||
|
|
||
|
return DIV_ROUND_CLOSEST(value.intval, 10);
|
||
|
}
|
||
|
|
||
|
void tas25xx_update_big_data(void)
|
||
|
{
|
||
|
uint8_t iter = 0;
|
||
|
uint32_t data[8] = {0};
|
||
|
uint32_t param_id = 0;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
if (!p_tas25xx_algo) {
|
||
|
pr_err("[TI-SmartPA:%s] memory not allocated yet for p_tas25xx_algo",
|
||
|
__func__);
|
||
|
}
|
||
|
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
/*Reset data*/
|
||
|
memset(data, 0, 8*sizeof(uint32_t));
|
||
|
param_id = (TAS_SA_EXC_TEMP_STAT)|((iter+1)<<24)
|
||
|
|((sizeof(data)/sizeof(uint32_t))<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)(&(data[0])), param_id
|
||
|
, TAS_GET_PARAM, sizeof(data));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s] Failed to get Excursion and Temperature Stats",
|
||
|
__func__);
|
||
|
} else {
|
||
|
pr_err("[TI-SmartPA:%s] Emax[%d] %d(%02d.%02d), Tmax[%d] %d, EOcount[%d] %d, TOcount[%d] %d \n",
|
||
|
__func__, iter,
|
||
|
data[0], (int32_t)trans_val_to_user_i(data[0], QFORMAT31),
|
||
|
(int32_t)trans_val_to_user_m(data[0], QFORMAT31),
|
||
|
iter, data[1], iter, data[2], iter, data[3]);
|
||
|
|
||
|
/*Update Excursion Data*/
|
||
|
p_tas25xx_algo->b_data[iter].exc_max =
|
||
|
(data[0] > p_tas25xx_algo->b_data[iter].exc_max)
|
||
|
? data[0]:p_tas25xx_algo->b_data[iter].exc_max;
|
||
|
p_tas25xx_algo->b_data[iter].exc_max_persist =
|
||
|
(data[0] > p_tas25xx_algo->b_data[iter].exc_max_persist)
|
||
|
? data[0]:p_tas25xx_algo->b_data[iter].exc_max_persist;
|
||
|
p_tas25xx_algo->b_data[iter].exc_over_count += data[2];
|
||
|
|
||
|
/*Update Temperature Data*/
|
||
|
p_tas25xx_algo->b_data[iter].temp_max =
|
||
|
(data[1] > p_tas25xx_algo->b_data[iter].temp_max)
|
||
|
? data[1]:p_tas25xx_algo->b_data[iter].temp_max;
|
||
|
p_tas25xx_algo->b_data[iter].temp_max_persist =
|
||
|
(data[1] > p_tas25xx_algo->b_data[iter].temp_max_persist)
|
||
|
? data[1]:p_tas25xx_algo->b_data[iter].temp_max_persist;
|
||
|
p_tas25xx_algo->b_data[iter].temp_over_count += data[3];
|
||
|
}
|
||
|
|
||
|
memset(data, 0, 8*sizeof(uint32_t));
|
||
|
param_id = (TAS_SA_LE_FLAG_STATS)|((iter+1)<<24)
|
||
|
|((sizeof(data)/sizeof(uint32_t))<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)(&(data[0])), param_id,
|
||
|
TAS_GET_PARAM, sizeof(data));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s] Failed to get LE flag info\n",
|
||
|
__func__);
|
||
|
} else {
|
||
|
u64 temp = 0;
|
||
|
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_detected = data[0];
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_count = data[1];
|
||
|
temp = data[1] + p_tas25xx_algo->b_le_flag[iter].le_flag_count_persist;
|
||
|
if ((temp - data[1]) == p_tas25xx_algo->b_le_flag[iter].le_flag_count_persist)
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_count_persist = temp;
|
||
|
else
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_count_persist = U64_MAX;
|
||
|
|
||
|
pr_info("[TI-SmartPA:%s] LE Flag Detection Ch=%d detected=%u, count=%u, Total Count=%llu\n",
|
||
|
__func__, iter, p_tas25xx_algo->b_le_flag[iter].le_flag_detected,
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_count,
|
||
|
p_tas25xx_algo->b_le_flag[iter].le_flag_count_persist);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int tas25xx_update_calibration_limits(void)
|
||
|
{
|
||
|
uint8_t iter = 0;
|
||
|
uint32_t param_id = 0;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
/*Reset Calibration Result*/
|
||
|
memset(calibration_result, STATUS_NONE, sizeof(uint8_t)*MAX_CHANNELS);
|
||
|
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
/*Update Lower limit for calibration*/
|
||
|
re_low[iter] = 0;//Reset data to 0
|
||
|
param_id = ((TAS_SA_GET_RE_LOW)|((iter+1)<<24)|(1<<16));
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&re_low[iter], param_id,
|
||
|
TAS_GET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s]get re low fail channel no %d Exiting ..\n",
|
||
|
__func__, iter);
|
||
|
return ret;
|
||
|
}
|
||
|
re_low[iter] = re_low[iter] >> 8; /* Qformat 27 -> 19*/
|
||
|
/*Update Upper limit for calibration*/
|
||
|
re_high[iter] = 0;//Reset data to 0
|
||
|
param_id = ((TAS_SA_GET_RE_HIGH)|((iter+1)<<24)|(1<<16));
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&re_high[iter], param_id,
|
||
|
TAS_GET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s]get re high fail channel no %d Exiting ..\n",
|
||
|
__func__, iter);
|
||
|
return ret;
|
||
|
}
|
||
|
re_high[iter] = re_high[iter] >> 8; /* Qformat 27 -> 19*/
|
||
|
pr_err("[TI-SmartPA:%s] Channel No:%d, Rdc Limits(%02d.%02d ~ %02d.%02d) \n",
|
||
|
__func__, iter,
|
||
|
(int32_t)trans_val_to_user_i(re_low[iter], QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(re_low[iter], QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_i(re_high[iter], QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(re_high[iter], QFORMAT19));
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int tas25xx_check_limits(uint8_t channel, int32_t rdc)
|
||
|
{
|
||
|
if ((rdc >= re_low[channel]) && (rdc <= re_high[channel])) {
|
||
|
calibration_result[channel] = STATUS_SUCCESS;
|
||
|
return 1;
|
||
|
}
|
||
|
calibration_result[channel] = STATUS_FAIL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void tas25xx_send_algo_calibration(void)
|
||
|
{
|
||
|
uint32_t data = 0;
|
||
|
uint32_t param_id = 0;
|
||
|
uint8_t iter;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
if (!p_tas25xx_algo)
|
||
|
pr_err("[TI-SmartPA:%s] memory not allocated yet for p_tas25xx_algo",
|
||
|
__func__);
|
||
|
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
if (p_tas25xx_algo->calib_update[iter]) {
|
||
|
/*Set ambient temperature*/
|
||
|
data = p_tas25xx_algo->amb_temp[iter];
|
||
|
pr_info("[TI-SmartPA:%s] amb_temp[%d] %d",
|
||
|
__func__, iter, data);
|
||
|
param_id = (TAS_SA_SET_TCAL)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id,
|
||
|
TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
/*Set Re*/
|
||
|
data = p_tas25xx_algo->calib_re[iter];
|
||
|
pr_info("[TI-SmartPA:%s]calib_re[%d] is %02d.%02d (%d) \n",
|
||
|
__func__,
|
||
|
iter,
|
||
|
(int32_t)trans_val_to_user_i(data, QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(data, QFORMAT19),
|
||
|
(int32_t)data);
|
||
|
param_id = (TAS_SA_SET_RE)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id,
|
||
|
TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool tas25xx_set_iv_bit_fomat(int iv_data_with, int vbat, int update_now)
|
||
|
{
|
||
|
int32_t param_id;
|
||
|
int32_t ret;
|
||
|
bool success;
|
||
|
|
||
|
if ((vbat == 1) && (iv_data_with == 12))
|
||
|
g_iv_vbat_fmt = IV_SENSE_FORMAT_12_BIT_WITH_8BIT_VBAT;
|
||
|
else if ((vbat == 1) && (iv_data_with == 8))
|
||
|
g_iv_vbat_fmt = IV_SENSE_FORMAT_8_BIT_WITH_8BIT_VBAT;
|
||
|
else
|
||
|
g_iv_vbat_fmt = IV_SENSE_FORMAT_NO_VBAT;
|
||
|
|
||
|
success = true;
|
||
|
|
||
|
if (update_now) {
|
||
|
param_id = (TAS_SA_IV_VBAT_FMT) | (1<<24) | (1<<16);
|
||
|
pr_info("TI-SmartPA: %s: Sending IV,Vbat format %d\n", __func__, g_iv_vbat_fmt);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&g_iv_vbat_fmt, param_id,
|
||
|
TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
pr_err("TI-SmartPA: %s: Failed to set config for iv-vbat data format\n", __func__);
|
||
|
success = false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
static int tas25xx_save_calib_data(uint32_t *calib_rdc)
|
||
|
{
|
||
|
uint8_t iter = 0;
|
||
|
int ret = 0;
|
||
|
|
||
|
if (!calib_rdc) {
|
||
|
pr_err("[TI-SmartPA:%s] argument is Null", __func__);
|
||
|
ret = -1;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
calib_re_hold[iter] = calib_rdc[iter];
|
||
|
amb_temp_hold[iter] = tas25xx_get_amb_temp();
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**********Calibration Related Codes Start******************/
|
||
|
static void calib_work_routine(struct work_struct *work)
|
||
|
{
|
||
|
uint8_t iter = 0, iter2 = 0;
|
||
|
uint32_t data = 0;
|
||
|
uint32_t param_id = 0;
|
||
|
uint32_t calib_re[MAX_CHANNELS] = {0};
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
if (tas25xx_update_calibration_limits())
|
||
|
return;
|
||
|
|
||
|
/*Get Re*/
|
||
|
for (iter2 = 0; iter2 < CALIB_RETRY_COUNT; iter2++) {
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
if (calibration_result[iter] == STATUS_SUCCESS)
|
||
|
continue;
|
||
|
|
||
|
/*Calinration Init*/
|
||
|
data = 1;/*Value is ignored*/
|
||
|
param_id = (TAS_SA_CALIB_INIT)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id
|
||
|
, TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s] Init error. Exiting ..", __func__);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
msleep(CALIB_TIME*1000);
|
||
|
|
||
|
data = 0;//Reset data to 0
|
||
|
param_id = ((TAS_SA_GET_RE)|((iter+1)<<24)|(1<<16));
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id,
|
||
|
TAS_GET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
calibration_result[iter] = STATUS_FAIL;
|
||
|
pr_info("[TI-SmartPA:%s]get re fail. Exiting ..\n", __func__);
|
||
|
} else {
|
||
|
calib_re[iter] = data;
|
||
|
pr_info("[TI-SmartPA:%s]calib_re is %02d.%02d (%d) \n",
|
||
|
__func__,
|
||
|
(int32_t)trans_val_to_user_i(calib_re[iter], QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(calib_re[iter], QFORMAT19),
|
||
|
(int32_t)calib_re[iter]);
|
||
|
if (tas25xx_check_limits(iter, calib_re[iter]))
|
||
|
pr_info("[TI-SmartPA:%s] Calibration Pass Channel No:%d",
|
||
|
__func__, iter);
|
||
|
}
|
||
|
|
||
|
/*Calibration De-Init*/
|
||
|
data = 1;//Value is ignored
|
||
|
param_id = (TAS_SA_CALIB_DEINIT)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id
|
||
|
, TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
/*Wait some time*/
|
||
|
msleep(200);
|
||
|
}
|
||
|
}
|
||
|
tas25xx_save_calib_data(calib_re);
|
||
|
|
||
|
calibration_status = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(calibration, 0664, tas25xx_calib_calibration_show,
|
||
|
tas25xx_calib_calibration_store);
|
||
|
|
||
|
static DEVICE_ATTR(cstatus, 0664, tas25xx_calib_status_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(rdc, 0664, tas25xx_calib_rdc_show,
|
||
|
tas25xx_calib_rdc_store);
|
||
|
|
||
|
static DEVICE_ATTR(temp, 0664, tas25xx_amb_temp_show,
|
||
|
tas25xx_amb_temp_store);
|
||
|
|
||
|
static DEVICE_ATTR(cstatus_r, 0664, tas25xx_calib_status_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(rdc_r, 0664, tas25xx_calib_rdc_show,
|
||
|
tas25xx_calib_rdc_store);
|
||
|
|
||
|
static DEVICE_ATTR(temp_r, 0664, tas25xx_amb_temp_show,
|
||
|
tas25xx_amb_temp_store);
|
||
|
|
||
|
static ssize_t tas25xx_calib_calibration_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t size)
|
||
|
{
|
||
|
int32_t ret = 0;
|
||
|
int32_t start;
|
||
|
|
||
|
ret = kstrtos32(buf, 10, &start);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s] Invalid input", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
|
||
|
if (start) {
|
||
|
calibration_status = 1;
|
||
|
/*Give time for algorithm to converge rdc*/
|
||
|
schedule_delayed_work(&p_tas25xx_algo->calib_work,
|
||
|
msecs_to_jiffies(200));
|
||
|
}
|
||
|
end:
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_calib_calibration_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
/*Enough to check for only one channel*/
|
||
|
return snprintf(buf, MAX_STRING, "%s\n",
|
||
|
(calibration_status) ? "Enabled" : "Disabled");
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_calib_status_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
ssize_t ret = 0;
|
||
|
|
||
|
if (attr == &dev_attr_cstatus_r)
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", calibration_result[1]);
|
||
|
else
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", calibration_result[0]);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_calib_rdc_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
uint32_t calib_re = 0;
|
||
|
|
||
|
if (attr == &dev_attr_rdc_r) {
|
||
|
if (calibration_result[1] == STATUS_NONE) {
|
||
|
if (p_tas25xx_algo->calib_update[1])
|
||
|
calib_re = p_tas25xx_algo->calib_re[1];
|
||
|
} else
|
||
|
calib_re = calib_re_hold[1];
|
||
|
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(calib_re, QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(calib_re, QFORMAT19));
|
||
|
} else {
|
||
|
if (calibration_result[0] == STATUS_NONE) {
|
||
|
if (p_tas25xx_algo->calib_update[0])
|
||
|
calib_re = p_tas25xx_algo->calib_re[0];
|
||
|
} else
|
||
|
calib_re = calib_re_hold[0];
|
||
|
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(calib_re, QFORMAT19),
|
||
|
(int32_t)trans_val_to_user_m(calib_re, QFORMAT19));
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_calib_rdc_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t size)
|
||
|
{
|
||
|
uint32_t data_flt[2];
|
||
|
int ret = 0;
|
||
|
|
||
|
ret = sscanf(buf, "%d.%d", &(data_flt[0]),
|
||
|
&(data_flt[1]));
|
||
|
if (ret != 2) {
|
||
|
pr_err("[TI-SmartPA:%s] read error\n", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
if (attr == &dev_attr_rdc_r)
|
||
|
p_tas25xx_algo->calib_re[1] = TRANSF_USER_TO_IMPED(data_flt[0], data_flt[1]);
|
||
|
else
|
||
|
p_tas25xx_algo->calib_re[0] = TRANSF_USER_TO_IMPED(data_flt[0], data_flt[1]);
|
||
|
end:
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_amb_temp_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
uint32_t amb_temp = 0;
|
||
|
|
||
|
if (attr == &dev_attr_temp_r) {
|
||
|
if (calibration_result[1] == STATUS_NONE) {
|
||
|
if (p_tas25xx_algo->calib_update[1])
|
||
|
amb_temp = p_tas25xx_algo->amb_temp[1];
|
||
|
} else
|
||
|
amb_temp = amb_temp_hold[1];
|
||
|
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", amb_temp);
|
||
|
} else {
|
||
|
if (calibration_result[0] == STATUS_NONE) {
|
||
|
if (p_tas25xx_algo->calib_update[0])
|
||
|
amb_temp = p_tas25xx_algo->amb_temp[0];
|
||
|
} else
|
||
|
amb_temp = amb_temp_hold[0];
|
||
|
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", amb_temp);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_amb_temp_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t size)
|
||
|
{
|
||
|
uint32_t data;
|
||
|
int ret = 0;
|
||
|
|
||
|
ret = sscanf(buf, "%d", &data);
|
||
|
if (ret != 1) {
|
||
|
pr_err("[TI-SmartPA:%s] read error\n", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
if (attr == &dev_attr_temp_r) {
|
||
|
p_tas25xx_algo->amb_temp[1] = data;
|
||
|
p_tas25xx_algo->calib_update[1] = true;
|
||
|
} else {
|
||
|
p_tas25xx_algo->amb_temp[0] = data;
|
||
|
p_tas25xx_algo->calib_update[0] = true;
|
||
|
}
|
||
|
end:
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static struct attribute *tas25xx_calib_attr[] = {
|
||
|
&dev_attr_calibration.attr,
|
||
|
&dev_attr_cstatus.attr,
|
||
|
&dev_attr_rdc.attr,
|
||
|
&dev_attr_temp.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_calib_attr_r[] = {
|
||
|
&dev_attr_cstatus_r.attr,
|
||
|
&dev_attr_rdc_r.attr,
|
||
|
&dev_attr_temp_r.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_calib_attr_m[
|
||
|
ARRAY_SIZE(tas25xx_calib_attr) +
|
||
|
ARRAY_SIZE(tas25xx_calib_attr_r) + 1] = {NULL};
|
||
|
|
||
|
static struct attribute_group tas25xx_calib_attr_grp = {
|
||
|
.attrs = tas25xx_calib_attr_m,
|
||
|
};
|
||
|
|
||
|
/*******************Calibration Related Codes End***********************/
|
||
|
/*******************Validation Related Codes Start**********************/
|
||
|
static void valid_work_routine(struct work_struct *work)
|
||
|
{
|
||
|
uint8_t iter = 0;
|
||
|
uint32_t data = 0;
|
||
|
uint32_t param_id = 0;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
//Validation Status Check
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
data = 0;//Reset data to 0
|
||
|
param_id = ((TAS_SA_GET_VALID_STATUS)|((iter+1)<<24)|(1<<16));
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id,
|
||
|
TAS_GET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
validation_result[iter] = STATUS_FAIL;
|
||
|
pr_info("[TI-SmartPA:%s]status read failed \n", __func__);
|
||
|
} else {
|
||
|
if (data == VALIDATION_SUCCESS) {
|
||
|
validation_result[iter] = STATUS_SUCCESS;
|
||
|
} else {
|
||
|
validation_result[iter] = STATUS_FAIL;
|
||
|
}
|
||
|
}
|
||
|
pr_info("[TI-SmartPA:%s] Channel-%d", __func__, iter);
|
||
|
pr_info("[TI-SmartPA:%s] validation_result %s(0x%x)\n", __func__,
|
||
|
validation_result[iter] == STATUS_SUCCESS ? "Success":"Fail", (int32_t)data);
|
||
|
|
||
|
/*De-Init the validation process*/
|
||
|
data = 0;//Value is ignored
|
||
|
param_id = (TAS_SA_VALID_DEINIT)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id,
|
||
|
TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
}
|
||
|
validation_running_status = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(validation, 0644, tas25xx_valid_validation_show,
|
||
|
tas25xx_valid_validation_store);
|
||
|
|
||
|
static DEVICE_ATTR(status, 0644, tas25xx_valid_status_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(status_r, 0644, tas25xx_valid_status_show,
|
||
|
NULL);
|
||
|
|
||
|
static ssize_t tas25xx_valid_validation_store(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t size)
|
||
|
{
|
||
|
uint8_t iter = 0;
|
||
|
uint32_t data = 0;
|
||
|
uint32_t param_id = 0;
|
||
|
int32_t start = 0;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
ret = kstrtos32(buf, 10, &start);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s] Invalid input", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
|
||
|
if (start) {
|
||
|
//Init
|
||
|
for (iter = 0; iter < p_tas25xx_algo->spk_count; iter++) {
|
||
|
data = 1;/*Value is ignored*/
|
||
|
param_id = (TAS_SA_VALID_INIT)|((iter+1)<<24)|(1<<16);
|
||
|
ret = afe_smartamp_algo_ctrl((u8 *)&data, param_id
|
||
|
, TAS_SET_PARAM, sizeof(uint32_t));
|
||
|
if (ret < 0) {
|
||
|
pr_err("[TI-SmartPA:%s] Init error. Exiting ..", __func__);
|
||
|
goto end;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Give time for algorithm to converge V-sns level
|
||
|
validation_running_status = 1;
|
||
|
schedule_delayed_work(&p_tas25xx_algo->valid_work,
|
||
|
msecs_to_jiffies(VALIDATION_TIME * 1000));
|
||
|
}
|
||
|
end:
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_valid_validation_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
return snprintf(buf, MAX_STRING, "%s\n",
|
||
|
(validation_running_status) ? "Enabled" : "Disabled");
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_valid_status_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_status_r)
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", validation_result[1]);
|
||
|
else
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", validation_result[0]);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static struct attribute *tas25xx_valid_attr[] = {
|
||
|
&dev_attr_validation.attr,
|
||
|
&dev_attr_status.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_valid_attr_r[] = {
|
||
|
&dev_attr_status_r.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_valid_attr_m[
|
||
|
ARRAY_SIZE(tas25xx_valid_attr) +
|
||
|
ARRAY_SIZE(tas25xx_valid_attr_r) + 1] = {NULL};
|
||
|
|
||
|
static struct attribute_group tas25xx_valid_attr_grp = {
|
||
|
.attrs = tas25xx_valid_attr_m,
|
||
|
};
|
||
|
/******************Validation Related Codes End***********************/
|
||
|
/******************BigData Related Codes Start************************/
|
||
|
|
||
|
static DEVICE_ATTR(exc_max, 0664,
|
||
|
tas25xx_bd_exc_max_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(exc_max_persist, 0664,
|
||
|
tas25xx_bd_exc_max_persist_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(exc_over_count, 0664,
|
||
|
tas25xx_bd_exc_over_count_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_max, 0664,
|
||
|
tas25xx_bd_temp_max_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_max_persist, 0664,
|
||
|
tas25xx_bd_temp_max_persist_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_over_count, 0664,
|
||
|
tas25xx_bd_temp_over_count_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(exc_max_r, 0664,
|
||
|
tas25xx_bd_exc_max_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(exc_max_persist_r, 0664,
|
||
|
tas25xx_bd_exc_max_persist_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(exc_over_count_r, 0664,
|
||
|
tas25xx_bd_exc_over_count_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_max_r, 0664,
|
||
|
tas25xx_bd_temp_max_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_max_persist_r, 0664,
|
||
|
tas25xx_bd_temp_max_persist_show, NULL);
|
||
|
|
||
|
static DEVICE_ATTR(temp_over_count_r, 0664,
|
||
|
tas25xx_bd_temp_over_count_show, NULL);
|
||
|
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_detected, 0664, tas25xx_le_flag_deteced_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_count_persist, 0664, tas25xx_le_flag_count_persist_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_count, 0664, tas25xx_le_flag_count_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_detected_r, 0664, tas25xx_le_flag_deteced_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_count_persist_r, 0664, tas25xx_le_flag_count_persist_show,
|
||
|
NULL);
|
||
|
|
||
|
static DEVICE_ATTR(le_flag_count_r, 0664, tas25xx_le_flag_count_show,
|
||
|
NULL);
|
||
|
|
||
|
static ssize_t tas25xx_le_flag_deteced_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (!p_tas25xx_algo)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
if (attr == &dev_attr_le_flag_detected_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_le_flag[1].le_flag_detected);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_le_flag[0].le_flag_detected);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_le_flag_count_persist_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
if (!p_tas25xx_algo)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
if (attr == &dev_attr_le_flag_count_persist_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%llu",
|
||
|
p_tas25xx_algo->b_le_flag[1].le_flag_count_persist);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%llu",
|
||
|
p_tas25xx_algo->b_le_flag[0].le_flag_count_persist);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_le_flag_count_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
if (!p_tas25xx_algo)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
if (attr == &dev_attr_le_flag_count_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%lu",
|
||
|
(unsigned long)p_tas25xx_algo->b_le_flag[1].le_flag_count);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%lu",
|
||
|
(unsigned long)p_tas25xx_algo->b_le_flag[0].le_flag_count);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_exc_max_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_exc_max_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(p_tas25xx_algo->b_data[1].exc_max,
|
||
|
QFORMAT31),
|
||
|
(int32_t)trans_val_to_user_m(p_tas25xx_algo->b_data[1].exc_max,
|
||
|
QFORMAT31));
|
||
|
p_tas25xx_algo->b_data[1].exc_max = 0;
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(p_tas25xx_algo->b_data[0].exc_max,
|
||
|
QFORMAT31),
|
||
|
(int32_t)trans_val_to_user_m(p_tas25xx_algo->b_data[0].exc_max,
|
||
|
QFORMAT31));
|
||
|
p_tas25xx_algo->b_data[0].exc_max = 0;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_exc_max_persist_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_exc_max_persist_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(p_tas25xx_algo->b_data[1].exc_max_persist, QFORMAT31),
|
||
|
(int32_t)trans_val_to_user_m(p_tas25xx_algo->b_data[1].exc_max_persist, QFORMAT31));
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%02d.%02d",
|
||
|
(int32_t)trans_val_to_user_i(p_tas25xx_algo->b_data[0].exc_max_persist, QFORMAT31),
|
||
|
(int32_t)trans_val_to_user_m(p_tas25xx_algo->b_data[0].exc_max_persist, QFORMAT31));
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_exc_over_count_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_exc_over_count_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[1].exc_over_count);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[0].exc_over_count);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_temp_max_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_temp_max_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", p_tas25xx_algo->b_data[1].temp_max);
|
||
|
p_tas25xx_algo->b_data[1].temp_max = 0;
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d", p_tas25xx_algo->b_data[0].temp_max);
|
||
|
p_tas25xx_algo->b_data[0].temp_max = 0;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_temp_max_persist_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_temp_max_persist_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[1].temp_max_persist);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[0].temp_max_persist);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t tas25xx_bd_temp_over_count_show(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
ssize_t ret;
|
||
|
|
||
|
if (attr == &dev_attr_temp_over_count_r) {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[1].temp_over_count);
|
||
|
} else {
|
||
|
ret = snprintf(buf, MAX_STRING, "%d",
|
||
|
p_tas25xx_algo->b_data[0].temp_over_count);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static struct attribute *tas25xx_bd_attr[] = {
|
||
|
&dev_attr_exc_max.attr,
|
||
|
&dev_attr_exc_max_persist.attr,
|
||
|
&dev_attr_exc_over_count.attr,
|
||
|
&dev_attr_temp_max.attr,
|
||
|
&dev_attr_temp_max_persist.attr,
|
||
|
&dev_attr_temp_over_count.attr,
|
||
|
&dev_attr_le_flag_detected.attr,
|
||
|
&dev_attr_le_flag_count_persist.attr,
|
||
|
&dev_attr_le_flag_count.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_bd_attr_r[] = {
|
||
|
&dev_attr_exc_max_r.attr,
|
||
|
&dev_attr_exc_max_persist_r.attr,
|
||
|
&dev_attr_exc_over_count_r.attr,
|
||
|
&dev_attr_temp_max_r.attr,
|
||
|
&dev_attr_temp_max_persist_r.attr,
|
||
|
&dev_attr_temp_over_count_r.attr,
|
||
|
&dev_attr_le_flag_detected_r.attr,
|
||
|
&dev_attr_le_flag_count_persist_r.attr,
|
||
|
&dev_attr_le_flag_count_r.attr,
|
||
|
};
|
||
|
|
||
|
static struct attribute *tas25xx_bd_attr_m[
|
||
|
ARRAY_SIZE(tas25xx_bd_attr) +
|
||
|
ARRAY_SIZE(tas25xx_bd_attr_r) + 1] = {NULL};
|
||
|
|
||
|
static struct attribute_group tas25xx_bd_attr_grp = {
|
||
|
.attrs = tas25xx_bd_attr_m,
|
||
|
};
|
||
|
|
||
|
/*************BigData Related Codes End******************************/
|
||
|
|
||
|
static void clean_up_tas_sysfs(void)
|
||
|
{
|
||
|
if (p_tas25xx_algo) {
|
||
|
|
||
|
if (p_tas25xx_algo->calib_dev) {
|
||
|
sysfs_remove_group(&p_tas25xx_algo->calib_dev->kobj,
|
||
|
&tas25xx_calib_attr_grp);
|
||
|
device_destroy(p_tas25xx_algo->algo_class, 1);
|
||
|
}
|
||
|
|
||
|
if (p_tas25xx_algo->valid_dev) {
|
||
|
sysfs_remove_group(&p_tas25xx_algo->valid_dev->kobj,
|
||
|
&tas25xx_valid_attr_grp);
|
||
|
device_destroy(p_tas25xx_algo->algo_class, 1);
|
||
|
}
|
||
|
|
||
|
if (p_tas25xx_algo->bd_dev) {
|
||
|
sysfs_remove_group(&p_tas25xx_algo->bd_dev->kobj,
|
||
|
&tas25xx_bd_attr_grp);
|
||
|
device_destroy(p_tas25xx_algo->algo_class, 1);
|
||
|
}
|
||
|
|
||
|
if (p_tas25xx_algo->algo_class)
|
||
|
class_destroy(p_tas25xx_algo->algo_class);
|
||
|
|
||
|
kfree(p_tas25xx_algo);
|
||
|
p_tas25xx_algo = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void update_dts_info(void)
|
||
|
{
|
||
|
if (!p_tas25xx_algo) {
|
||
|
pr_err("[TI-SmartPA:%s] memory not allocated yet for p_tas25xx_algo",
|
||
|
__func__);
|
||
|
}
|
||
|
|
||
|
p_tas25xx_algo->port = port;
|
||
|
}
|
||
|
|
||
|
void tas25xx_parse_algo_dt(struct device_node *np)
|
||
|
{
|
||
|
uint32_t data = 0;
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
ret = of_property_read_u32(np, "ti,port_id", &data);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s] Looking up %s property in node %s failed %d\n",
|
||
|
__func__, "ti,port_id", np->full_name, ret);
|
||
|
} else {
|
||
|
port = data;
|
||
|
pr_err("[TI-SmartPA:%s] ti,port_id=0x%x",
|
||
|
__func__, data);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
void smartamp_add_algo(uint8_t channels)
|
||
|
{
|
||
|
int32_t ret = 0;
|
||
|
|
||
|
pr_err("[TI-SmartPA:%s] Adding Smartamp algo functions, spk_count=%d",
|
||
|
__func__, channels);
|
||
|
|
||
|
mutex_init(&routing_lock);
|
||
|
|
||
|
p_tas25xx_algo = kzalloc(sizeof(struct tas25xx_algo), GFP_KERNEL);
|
||
|
if (p_tas25xx_algo == NULL) {
|
||
|
pr_err("[TI-SmartPA:%s] No Memory", __func__);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p_tas25xx_algo->spk_count = channels;
|
||
|
|
||
|
memcpy(tas25xx_calib_attr_m, tas25xx_calib_attr,
|
||
|
sizeof(tas25xx_calib_attr));
|
||
|
memcpy(tas25xx_valid_attr_m, tas25xx_valid_attr,
|
||
|
sizeof(tas25xx_valid_attr));
|
||
|
memcpy(tas25xx_bd_attr_m, tas25xx_bd_attr, sizeof(tas25xx_bd_attr));
|
||
|
if (channels == 2) {
|
||
|
memcpy(tas25xx_calib_attr_m + ARRAY_SIZE(tas25xx_calib_attr),
|
||
|
tas25xx_calib_attr_r, sizeof(tas25xx_calib_attr_r));
|
||
|
memcpy(tas25xx_valid_attr_m + ARRAY_SIZE(tas25xx_valid_attr),
|
||
|
tas25xx_valid_attr_r, sizeof(tas25xx_valid_attr_r));
|
||
|
memcpy(tas25xx_bd_attr_m + ARRAY_SIZE(tas25xx_bd_attr),
|
||
|
tas25xx_bd_attr_r, sizeof(tas25xx_bd_attr_r));
|
||
|
}
|
||
|
|
||
|
update_dts_info();
|
||
|
|
||
|
p_tas25xx_algo->algo_class = class_create(THIS_MODULE,
|
||
|
TAS25XX_SYSFS_CLASS_NAME);
|
||
|
if (IS_ERR(p_tas25xx_algo->algo_class)) {
|
||
|
ret = PTR_ERR(p_tas25xx_algo->algo_class);
|
||
|
pr_err("[TI-SmartPA:%s] err class create\n", __func__);
|
||
|
p_tas25xx_algo->algo_class = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
p_tas25xx_algo->calib_dev = device_create(p_tas25xx_algo->algo_class,
|
||
|
NULL, 1, NULL, TAS25XX_CALIB_DIR_NAME);
|
||
|
if (IS_ERR(p_tas25xx_algo->calib_dev)) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create calib_dev\n", __func__);
|
||
|
ret = PTR_ERR(p_tas25xx_algo->calib_dev);
|
||
|
p_tas25xx_algo->calib_dev = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
ret = sysfs_create_group(&p_tas25xx_algo->calib_dev->kobj,
|
||
|
&tas25xx_calib_attr_grp);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create sysfs group\n",
|
||
|
__func__);
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
INIT_DELAYED_WORK(&p_tas25xx_algo->calib_work, calib_work_routine);
|
||
|
|
||
|
p_tas25xx_algo->valid_dev = device_create(p_tas25xx_algo->algo_class,
|
||
|
NULL, 1, NULL, TAS25XX_VALID_DIR_NAME);
|
||
|
if (IS_ERR(p_tas25xx_algo->valid_dev)) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create valid_dev\n", __func__);
|
||
|
ret = PTR_ERR(p_tas25xx_algo->valid_dev);
|
||
|
p_tas25xx_algo->valid_dev = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
ret = sysfs_create_group(&p_tas25xx_algo->valid_dev->kobj,
|
||
|
&tas25xx_valid_attr_grp);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create sysfs group\n",
|
||
|
__func__);
|
||
|
p_tas25xx_algo->valid_dev = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
INIT_DELAYED_WORK(&p_tas25xx_algo->valid_work, valid_work_routine);
|
||
|
p_tas25xx_algo->bd_dev = device_create(p_tas25xx_algo->algo_class,
|
||
|
NULL, 1, NULL, TAS25XX_BD_DIR_NAME);
|
||
|
if (IS_ERR(p_tas25xx_algo->bd_dev)) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create bd_dev\n", __func__);
|
||
|
ret = PTR_ERR(p_tas25xx_algo->bd_dev);
|
||
|
p_tas25xx_algo->bd_dev = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
ret = sysfs_create_group(&p_tas25xx_algo->bd_dev->kobj,
|
||
|
&tas25xx_bd_attr_grp);
|
||
|
if (ret) {
|
||
|
pr_err("[TI-SmartPA:%s]Failed to create sysfs group\n",
|
||
|
__func__);
|
||
|
p_tas25xx_algo->bd_dev = NULL;
|
||
|
goto err_dev;
|
||
|
}
|
||
|
|
||
|
pr_info("[TI-SmartPA:%s] ret=%d", __func__, ret);
|
||
|
return;
|
||
|
|
||
|
err_dev:
|
||
|
clean_up_tas_sysfs();
|
||
|
pr_err("[TI-SmartPA:%s] Error %d", __func__, ret);
|
||
|
}
|
||
|
|
||
|
void smartamp_remove_algo(void)
|
||
|
{
|
||
|
pr_info("[TI-SmartPA:%s] Removing Smartamp Algorithm functions",
|
||
|
__func__);
|
||
|
clean_up_tas_sysfs();
|
||
|
mutex_destroy(&routing_lock);
|
||
|
}
|
||
|
|
||
|
MODULE_AUTHOR("Texas Instruments Inc.");
|
||
|
MODULE_DESCRIPTION("TAS25XX Algorithm");
|
||
|
MODULE_LICENSE("GPL v2");
|
||
|
|
||
|
#endif /*CONFIG_TAS25XX_ALGO*/
|