c05564c4d8
Android 13
689 lines
19 KiB
C
Executable file
689 lines
19 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* mtk-scp-ultra-platform.c -- Mediatek scp ultra platform
|
|
*
|
|
* Copyright (c) 2018 MediaTek Inc.
|
|
* Author: Shane Chien <shane.chien@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/string.h>
|
|
#include <linux/spinlock.h>
|
|
#include <asm/arch_timer.h>
|
|
#include <sound/soc.h>
|
|
#include <linux/pm_wakeup.h>
|
|
#include <linux/pm_runtime.h>
|
|
|
|
#include "scp_helper.h"
|
|
#include "scp_excep.h"
|
|
#include "audio_ultra_msg_id.h"
|
|
#include "mtk-scp-ultra-mem-control.h"
|
|
#include "mtk-scp-ultra-platform-driver.h"
|
|
#include "mtk-base-scp-ultra.h"
|
|
#include "mtk-scp-ultra-common.h"
|
|
#include "mtk-base-afe.h"
|
|
#include "ultra_ipi.h"
|
|
#include "mtk-scp-ultra_dump.h"
|
|
#include "scp_feature_define.h"
|
|
|
|
|
|
//static DEFINE_SPINLOCK(scp_ultra_ringbuf_lock);
|
|
|
|
#define GET_SYSTEM_TIMER_CYCLE(void) \
|
|
({ \
|
|
unsigned long long __ret = arch_counter_get_cntvct(); \
|
|
__ret; \
|
|
})
|
|
#define ultra_IPIMSG_TIMEOUT (50)
|
|
#define ultra_WAITCHECK_INTERVAL_MS (2)
|
|
static bool ultra_ipi_wait;
|
|
static struct wakeup_source *ultra_suspend_lock;
|
|
static bool pcm_dump_switch;
|
|
static bool pcm_dump_on;
|
|
static const char *const mtk_scp_ultra_dump_str[] = {
|
|
"Off",
|
|
"On"};
|
|
|
|
static struct ultra_param_config param_config = {
|
|
.rate_in = 48000,
|
|
.rate_out = 48000,
|
|
.channel_in = 2,
|
|
.channel_out = 2,
|
|
.format_in = HAL_FORMAT_S16_LE,
|
|
.format_out = HAL_FORMAT_S16_LE,
|
|
.period_in_size = DEFAULT_UL_PERIOD_SIZE,
|
|
.period_out_size = DEFAULT_DL_PERIOD_SIZE,
|
|
.target_out_channel = ULTRASOUND_TARGET_OUT_CHANNEL_LEFT
|
|
};
|
|
|
|
static struct ultra_gain_config gain_config = {
|
|
.mic_gain = 0,
|
|
.receiver_gain = 0
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* SCP Recovery Register
|
|
*****************************************************************************/
|
|
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
|
|
static int usnd_scp_recover_event(struct notifier_block *this,
|
|
unsigned long event,
|
|
void *ptr)
|
|
{
|
|
switch (event) {
|
|
case SCP_EVENT_READY: {
|
|
pr_info("%s(), SCP_EVENT_READY\n", __func__);
|
|
ultra_SetScpRecoverStatus(false);
|
|
break;
|
|
}
|
|
case SCP_EVENT_STOP:
|
|
ultra_SetScpRecoverStatus(true);
|
|
pr_info("%s(), SCP_EVENT_STOP\n", __func__);
|
|
break;
|
|
}
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
static struct notifier_block usnd_scp_recover_notifier = {
|
|
.notifier_call = usnd_scp_recover_event,
|
|
};
|
|
#endif /* #ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT */
|
|
|
|
|
|
void ultra_ipi_rx_internal(unsigned int msg_id, void *msg_data)
|
|
{
|
|
switch (msg_id) {
|
|
case AUDIO_TASK_USND_MSG_ID_PCMDUMP_OK: {
|
|
ultra_dump_message(msg_data);
|
|
break;
|
|
}
|
|
case AUDIO_TASK_USND_MSG_ID_DEBUG:
|
|
{
|
|
pr_debug("%s(), AUDIO_TASK_USND_MSG_ID_DEBUG \r", __func__);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
bool ultra_ipi_rceive_ack(unsigned int msg_id,
|
|
unsigned int msg_data)
|
|
{
|
|
bool result = false;
|
|
|
|
switch (msg_id) {
|
|
case AUDIO_TASK_USND_MSG_ID_OFF:
|
|
case AUDIO_TASK_USND_MSG_ID_ON:
|
|
case AUDIO_TASK_USND_MSG_ID_START:
|
|
case AUDIO_TASK_USND_MSG_ID_STOP:
|
|
case AUDIO_TASK_USND_MSG_ID_PCMDUMP_OK:
|
|
result = true;
|
|
break;
|
|
default:
|
|
pr_info("%s(), no relate msg id(%d)\r", __func__, msg_id);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int mtk_scp_ultra_dump_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(cmpnt);
|
|
struct mtk_base_scp_ultra_dump *ultra_dump = &scp_ultra->ultra_dump;
|
|
|
|
dev_dbg(scp_ultra->dev, "%s()\n", __func__);
|
|
if (ucontrol->value.enumerated.item[0] >
|
|
ARRAY_SIZE(mtk_scp_ultra_dump_str)) {
|
|
dev_dbg(scp_ultra->dev, "return -EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
ucontrol->value.integer.value[0] = ultra_dump->dump_flag;
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_dump_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(cmpnt);
|
|
struct mtk_base_scp_ultra_dump *ultra_dump = &scp_ultra->ultra_dump;
|
|
//struct mtk_base_scp_ultra_mem *ultra_mem = &scp_ultra->ultra_mem;
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
static int ctrl_val;
|
|
int timeout = 0;
|
|
int payload[3];
|
|
bool ret_val;
|
|
|
|
dev_dbg(scp_ultra->dev, "%s(), value = %ld, dump_flag = %d\n",
|
|
__func__,
|
|
ucontrol->value.integer.value[0],
|
|
ultra_dump->dump_flag);
|
|
|
|
if (ultra_dump->dump_flag == false &&
|
|
ucontrol->value.integer.value[0] > 0) {
|
|
ctrl_val = ucontrol->value.integer.value[0];
|
|
ultra_dump->dump_flag = true;
|
|
pcm_dump_switch = true;
|
|
|
|
payload[0] = ultra_dump->dump_resv_mem.size;
|
|
payload[1] = ultra_dump->dump_resv_mem.phy_addr;
|
|
payload[2] = ultra_dump->dump_flag;
|
|
|
|
ret_val = ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_PCMDUMP_ON,
|
|
false,
|
|
3,
|
|
&payload[0],
|
|
ULTRA_IPI_BYPASS_ACK);
|
|
ultra_ipi_wait = true;
|
|
} else if (ultra_dump->dump_flag == true &&
|
|
ucontrol->value.integer.value[0] == 0) {
|
|
ultra_dump->dump_flag = false;
|
|
pcm_dump_switch = false;
|
|
|
|
while (ultra_ipi_wait) {
|
|
msleep(ultra_WAITCHECK_INTERVAL_MS);
|
|
if (timeout++ >= ultra_IPIMSG_TIMEOUT)
|
|
ultra_ipi_wait = false;
|
|
}
|
|
|
|
ret_val = ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_PCMDUMP_OFF,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_BYPASS_ACK);
|
|
/* scp ultra dump buffer use dram */
|
|
if (afe->release_dram_resource)
|
|
afe->release_dram_resource(afe->dev);
|
|
|
|
ctrl_val = ucontrol->value.integer.value[0];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const struct soc_enum mtk_scp_ultra_enum[] = {
|
|
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mtk_scp_ultra_dump_str),
|
|
mtk_scp_ultra_dump_str)
|
|
};
|
|
|
|
static int mtk_scp_ultra_param_config_get(struct snd_kcontrol *kcontrol,
|
|
unsigned int __user *data,
|
|
unsigned int size)
|
|
{
|
|
struct ultra_param_config *out_param_config = ¶m_config;
|
|
|
|
if (copy_to_user(data, out_param_config,
|
|
sizeof(struct ultra_param_config))) {
|
|
pr_info("%s() copy fail, data=%p, size=%d\n",
|
|
__func__, data, size);
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_param_config_set(struct snd_kcontrol *kcontrol,
|
|
const unsigned int __user *data,
|
|
unsigned int size)
|
|
{
|
|
if (copy_from_user(¶m_config,
|
|
data,
|
|
sizeof(struct ultra_param_config))) {
|
|
pr_info("%s() copy fail, data=%p, size=%d\n",
|
|
__func__, data, size);
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_gain_config_get(struct snd_kcontrol *kcontrol,
|
|
unsigned int __user *data,
|
|
unsigned int size)
|
|
{
|
|
struct ultra_gain_config *analog_gain_config = &gain_config;
|
|
|
|
if (copy_to_user(data,
|
|
analog_gain_config,
|
|
sizeof(struct ultra_gain_config))) {
|
|
pr_info("%s() copy fail, data=%p, size=%d\n",
|
|
__func__, data, size);
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_gain_config_set(struct snd_kcontrol *kcontrol,
|
|
const unsigned int __user *data,
|
|
unsigned int size)
|
|
{
|
|
int payload[2];
|
|
|
|
if (copy_from_user(&gain_config,
|
|
data,
|
|
sizeof(struct ultra_gain_config))) {
|
|
pr_info("%s() copy fail, data=%p, size=%d\n",
|
|
__func__, data, size);
|
|
return -EFAULT;
|
|
}
|
|
payload[0] = gain_config.mic_gain;
|
|
payload[1] = gain_config.receiver_gain;
|
|
pr_info("%s() mic_gain=%d, receiver_gain=%d\n",
|
|
__func__, gain_config.mic_gain, gain_config.receiver_gain);
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_ANALOG_GAIN,
|
|
false,
|
|
2,
|
|
&payload[0],
|
|
ULTRA_IPI_BYPASS_ACK);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int mtk_scp_ultra_engine_state_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct mtk_base_scp_ultra *scp_ultra = get_scp_ultra_base();
|
|
|
|
ucontrol->value.integer.value[0] = scp_ultra->usnd_state;
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_engine_state_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct mtk_base_scp_ultra *scp_ultra = get_scp_ultra_base();
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
struct mtk_base_scp_ultra_mem *ultra_mem = &scp_ultra->ultra_mem;
|
|
int scp_ultra_memif_dl_id;
|
|
int scp_ultra_memif_ul_id;
|
|
int val = ucontrol->value.integer.value[0];
|
|
int payload[7];
|
|
int old_usnd_state = scp_ultra->usnd_state;
|
|
bool ret_val = false;
|
|
|
|
if (val < SCP_ULTRA_STATE_IDLE || val > SCP_ULTRA_STATE_RECOVERY) {
|
|
pr_info("%s() unexpected state, ignore\n", __func__);
|
|
return -1;
|
|
}
|
|
scp_ultra->usnd_state = val;
|
|
|
|
scp_ultra_memif_dl_id =
|
|
scp_ultra->scp_ultra_dl_memif_id;
|
|
scp_ultra_memif_ul_id =
|
|
scp_ultra->scp_ultra_ul_memif_id;
|
|
ultra_mem->ultra_dl_memif_id = scp_ultra_memif_dl_id;
|
|
ultra_mem->ultra_ul_memif_id = scp_ultra_memif_ul_id;
|
|
pr_info("%s() new state=%d, memdl=%d, memul=%d\n",
|
|
__func__, scp_ultra->usnd_state,
|
|
scp_ultra_memif_dl_id,
|
|
scp_ultra_memif_ul_id);
|
|
switch (scp_ultra->usnd_state) {
|
|
case SCP_ULTRA_STATE_ON:
|
|
scp_register_feature(ULTRA_FEATURE_ID);
|
|
aud_wake_lock(ultra_suspend_lock);
|
|
|
|
afe->memif[scp_ultra_memif_dl_id].scp_ultra_enable = true;
|
|
afe->memif[scp_ultra_memif_ul_id].scp_ultra_enable = true;
|
|
|
|
payload[0] = param_config.rate_out;
|
|
payload[1] = param_config.channel_out;
|
|
payload[2] = param_config.period_out_size;
|
|
payload[3] = param_config.rate_in;
|
|
payload[4] = param_config.channel_in;
|
|
payload[5] = param_config.period_in_size;
|
|
payload[6] = param_config.target_out_channel;
|
|
ret_val = ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_ON,
|
|
false,
|
|
7,
|
|
&payload[0],
|
|
ULTRA_IPI_NEED_ACK);
|
|
if (ret_val == 0) {
|
|
pr_info("%s() set state on failed\n", __func__);
|
|
scp_ultra->usnd_state = SCP_ULTRA_STATE_IDLE;
|
|
afe->memif[scp_ultra_memif_dl_id].scp_ultra_enable =
|
|
false;
|
|
afe->memif[scp_ultra_memif_ul_id].scp_ultra_enable =
|
|
false;
|
|
scp_deregister_feature(ULTRA_FEATURE_ID);
|
|
aud_wake_unlock(ultra_suspend_lock);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
case SCP_ULTRA_STATE_OFF:
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_OFF,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_NEED_ACK);
|
|
scp_deregister_feature(ULTRA_FEATURE_ID);
|
|
aud_wake_unlock(ultra_suspend_lock);
|
|
return 0;
|
|
case SCP_ULTRA_STATE_START:
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_START,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_NEED_ACK);
|
|
return 0;
|
|
case SCP_ULTRA_STATE_STOP:
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_STOP,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_NEED_ACK);
|
|
return 0;
|
|
case SCP_ULTRA_STATE_RECOVERY:
|
|
if (old_usnd_state == SCP_ULTRA_STATE_OFF ||
|
|
old_usnd_state == SCP_ULTRA_STATE_IDLE ||
|
|
old_usnd_state == SCP_ULTRA_STATE_RECOVERY)
|
|
return 0;
|
|
pm_runtime_get_sync(afe->dev);
|
|
if (old_usnd_state == SCP_ULTRA_STATE_START)
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_STOP,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_NEED_ACK);
|
|
ultra_ipi_send(AUDIO_TASK_USND_MSG_ID_OFF,
|
|
false,
|
|
0,
|
|
NULL,
|
|
ULTRA_IPI_NEED_ACK);
|
|
scp_deregister_feature(ULTRA_FEATURE_ID);
|
|
pm_runtime_put(afe->dev);
|
|
aud_wake_unlock(ultra_suspend_lock);
|
|
return 0;
|
|
default:
|
|
pr_info("%s() err state, ignore\n", __func__);
|
|
return -1;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static const struct snd_kcontrol_new ultra_platform_kcontrols[] = {
|
|
SOC_ENUM_EXT("mtk_scp_ultra_pcm_dump",
|
|
mtk_scp_ultra_enum[0],
|
|
mtk_scp_ultra_dump_get,
|
|
mtk_scp_ultra_dump_set),
|
|
SND_SOC_BYTES_TLV("mtk_scp_ultra_param_config",
|
|
sizeof(struct ultra_param_config),
|
|
mtk_scp_ultra_param_config_get,
|
|
mtk_scp_ultra_param_config_set),
|
|
SND_SOC_BYTES_TLV("mtk_scp_ultra_gain_config",
|
|
sizeof(struct ultra_gain_config),
|
|
mtk_scp_ultra_gain_config_get,
|
|
mtk_scp_ultra_gain_config_set),
|
|
SOC_SINGLE_EXT("mtk_scp_ultra_engine_state",
|
|
SND_SOC_NOPM, 0, 0xff, 0,
|
|
mtk_scp_ultra_engine_state_get,
|
|
mtk_scp_ultra_engine_state_set),
|
|
};
|
|
|
|
static int mtk_scp_ultra_pcm_open(struct snd_pcm_substream *substream)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct snd_soc_component *component =
|
|
snd_soc_rtdcom_lookup(rtd, ULTRA_PCM_NAME);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_scp_ultra_mem *ultra_mem = &scp_ultra->ultra_mem;
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
int scp_ultra_memif_dl_id =
|
|
scp_ultra->scp_ultra_dl_memif_id;
|
|
int scp_ultra_memif_ul_id =
|
|
scp_ultra->scp_ultra_ul_memif_id;
|
|
|
|
ultra_mem->ultra_dl_memif_id = scp_ultra_memif_dl_id;
|
|
ultra_mem->ultra_ul_memif_id = scp_ultra_memif_ul_id;
|
|
|
|
memcpy((void *)(&(runtime->hw)), (void *)scp_ultra->mtk_scp_hardware,
|
|
sizeof(struct snd_pcm_hardware));
|
|
|
|
if (scp_ultra->ultra_mem.ultra_dl_memif_id < 0) {
|
|
dev_info(scp_ultra->dev, "%s() ultra_ul_memif_id<0, return\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
dev_info(scp_ultra->dev, "%s() memif dl=%d,ul=%d\n",
|
|
__func__,
|
|
scp_ultra->ultra_mem.ultra_dl_memif_id,
|
|
scp_ultra->ultra_mem.ultra_ul_memif_id);
|
|
|
|
if (pcm_dump_switch) {
|
|
/* scp ultra dump buffer use dram */
|
|
if (afe->request_dram_resource)
|
|
afe->request_dram_resource(afe->dev);
|
|
ultra_start_engine_thread();
|
|
pcm_dump_on = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int mtk_scp_ultra_pcm_start(struct snd_pcm_substream *substream)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
struct snd_soc_component *component =
|
|
snd_soc_rtdcom_lookup(rtd, ULTRA_PCM_NAME);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_scp_ultra_mem *ultra_mem = &scp_ultra->ultra_mem;
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
struct mtk_base_afe_memif *memif =
|
|
&afe->memif[ultra_mem->ultra_dl_memif_id];
|
|
struct mtk_base_afe_memif *memiful =
|
|
&afe->memif[ultra_mem->ultra_ul_memif_id];
|
|
int irq_id_dl = memif->irq_usage;
|
|
struct mtk_base_afe_irq *irqs_dl = &afe->irqs[irq_id_dl];
|
|
const struct mtk_base_irq_data *irq_data_dl = irqs_dl->irq_data;
|
|
int irq_id_ul = memiful->irq_usage;
|
|
struct mtk_base_afe_irq *irqs_ul = &afe->irqs[irq_id_ul];
|
|
const struct mtk_base_irq_data *irq_data_ul = irqs_ul->irq_data;
|
|
int counter;
|
|
|
|
/* Set dl&ul irq target to scp */
|
|
set_afe_dl_irq_target(true);
|
|
set_afe_ul_irq_target(true);
|
|
|
|
/* set dl irq counter */
|
|
counter = param_config.period_out_size;
|
|
regmap_update_bits(afe->regmap, irq_data_dl->irq_cnt_reg,
|
|
irq_data_dl->irq_cnt_maskbit
|
|
<< irq_data_dl->irq_cnt_shift,
|
|
counter << irq_data_dl->irq_cnt_shift);
|
|
|
|
/* start dl memif */
|
|
regmap_update_bits(afe->regmap,
|
|
memif->data->enable_reg,
|
|
1 << memif->data->enable_shift,
|
|
1 << memif->data->enable_shift);
|
|
|
|
/* set ul irq counter */
|
|
counter = param_config.period_in_size;
|
|
regmap_update_bits(afe->regmap, irq_data_ul->irq_cnt_reg,
|
|
irq_data_ul->irq_cnt_maskbit
|
|
<< irq_data_ul->irq_cnt_shift,
|
|
counter << irq_data_ul->irq_cnt_shift);
|
|
|
|
/* Start ul memif */
|
|
regmap_update_bits(afe->regmap,
|
|
memiful->data->enable_reg,
|
|
1 << memiful->data->enable_shift,
|
|
1 << memiful->data->enable_shift);
|
|
|
|
/* start ul irq */
|
|
regmap_update_bits(afe->regmap, irq_data_ul->irq_en_reg,
|
|
1 << irq_data_ul->irq_en_shift,
|
|
1 << irq_data_ul->irq_en_shift);
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_pcm_stop(struct snd_pcm_substream *substream)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
struct snd_soc_component *component =
|
|
snd_soc_rtdcom_lookup(rtd, ULTRA_PCM_NAME);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_scp_ultra_mem *ultra_mem = &scp_ultra->ultra_mem;
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
struct mtk_base_afe_memif *memif =
|
|
&afe->memif[ultra_mem->ultra_dl_memif_id];
|
|
struct mtk_base_afe_memif *memiful =
|
|
&afe->memif[ultra_mem->ultra_ul_memif_id];
|
|
int irq_id_dl = memif->irq_usage;
|
|
struct mtk_base_afe_irq *irqs_dl = &afe->irqs[irq_id_dl];
|
|
const struct mtk_base_irq_data *irq_data_dl = irqs_dl->irq_data;
|
|
int irq_id_ul = memiful->irq_usage;
|
|
struct mtk_base_afe_irq *irqs_ul = &afe->irqs[irq_id_ul];
|
|
const struct mtk_base_irq_data *irq_data_ul = irqs_ul->irq_data;
|
|
|
|
dev_info(scp_ultra->dev, "%s() dl_if=%d,ul_if=%d\n",
|
|
__func__,
|
|
ultra_mem->ultra_dl_memif_id,
|
|
ultra_mem->ultra_ul_memif_id);
|
|
|
|
if (scp_ultra->usnd_state == SCP_ULTRA_STATE_OFF) {
|
|
dev_info(scp_ultra->dev, "%s() ignore, state is off\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
/* stop dl memif */
|
|
regmap_update_bits(afe->regmap,
|
|
memif->data->enable_reg,
|
|
1 << memif->data->enable_shift,
|
|
0);
|
|
/* stop ul memif */
|
|
regmap_update_bits(afe->regmap,
|
|
memiful->data->enable_reg,
|
|
1 << memiful->data->enable_shift,
|
|
0);
|
|
/* stop dl irq */
|
|
regmap_update_bits(afe->regmap,
|
|
irq_data_dl->irq_en_reg,
|
|
1 << irq_data_dl->irq_en_shift,
|
|
0);
|
|
|
|
/* stop ul irq */
|
|
regmap_update_bits(afe->regmap, irq_data_ul->irq_en_reg,
|
|
1 << irq_data_ul->irq_en_shift,
|
|
0);
|
|
|
|
/* clear pending dl irq */
|
|
regmap_write(afe->regmap, irq_data_dl->irq_clr_reg,
|
|
1 << irq_data_dl->irq_clr_shift);
|
|
|
|
/* clear pending ul irq */
|
|
regmap_write(afe->regmap, irq_data_ul->irq_clr_reg,
|
|
1 << irq_data_ul->irq_clr_shift);
|
|
|
|
/* Set dl&ul irq to ap */
|
|
set_afe_dl_irq_target(false);
|
|
set_afe_ul_irq_target(false);
|
|
return 0;
|
|
}
|
|
static int mtk_scp_ultra_pcm_close(struct snd_pcm_substream *substream)
|
|
{
|
|
struct mtk_base_afe *afe = ultra_get_afe_base();
|
|
if (pcm_dump_on) {
|
|
/* scp ultra dump buffer use dram */
|
|
if (afe->release_dram_resource)
|
|
afe->release_dram_resource(afe->dev);
|
|
ultra_stop_engine_thread();
|
|
pcm_dump_on = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mtk_scp_ultra_pcm_hw_params_dl(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *params)
|
|
{
|
|
substream->runtime->dma_bytes = params_buffer_bytes(params);
|
|
}
|
|
|
|
static int mtk_scp_ultra_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *params)
|
|
{
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
mtk_scp_ultra_pcm_hw_params_dl(substream, params);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int mtk_scp_ultra_pcm_hw_prepare(struct snd_pcm_substream *substream)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int mtk_scp_ultra_pcm_hw_trigger(struct snd_pcm_substream *substream,
|
|
int cmd)
|
|
{
|
|
switch (cmd) {
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
return mtk_scp_ultra_pcm_start(substream);
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
return mtk_scp_ultra_pcm_stop(substream);
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int mtk_scp_ultra_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
|
{
|
|
struct snd_soc_component *component =
|
|
snd_soc_rtdcom_lookup(rtd, ULTRA_PCM_NAME);
|
|
struct mtk_base_scp_ultra *scp_ultra =
|
|
snd_soc_component_get_drvdata(component);
|
|
|
|
dev_info(scp_ultra->dev, "%s()\n", __func__);
|
|
|
|
snd_soc_add_component_controls(component,
|
|
ultra_platform_kcontrols,
|
|
ARRAY_SIZE(ultra_platform_kcontrols));
|
|
|
|
#ifdef CONFIG_MTK_TINYSYS_SCP_SUPPORT
|
|
scp_A_register_notify(&usnd_scp_recover_notifier);
|
|
#endif
|
|
ultra_suspend_lock = aud_wake_lock_init(NULL, "ultra wakelock");
|
|
pcm_dump_switch = false;
|
|
scp_ultra->usnd_state = SCP_ULTRA_STATE_IDLE;
|
|
return 0;
|
|
}
|
|
|
|
static const struct snd_pcm_ops mtk_scp_ultra_pcm_ops = {
|
|
.open = mtk_scp_ultra_pcm_open,
|
|
.close = mtk_scp_ultra_pcm_close,
|
|
.hw_params = mtk_scp_ultra_pcm_hw_params,
|
|
.prepare = mtk_scp_ultra_pcm_hw_prepare,
|
|
.trigger = mtk_scp_ultra_pcm_hw_trigger,
|
|
.ioctl = snd_pcm_lib_ioctl,
|
|
};
|
|
|
|
const struct snd_soc_component_driver mtk_scp_ultra_pcm_platform = {
|
|
.name = ULTRA_PCM_NAME,
|
|
.ops = &mtk_scp_ultra_pcm_ops,
|
|
.pcm_new = mtk_scp_ultra_pcm_new,
|
|
};
|
|
EXPORT_SYMBOL_GPL(mtk_scp_ultra_pcm_platform);
|
|
|
|
static int ultra_ipi_init(void)
|
|
{
|
|
ultra_ipi_register(ultra_ipi_rx_internal, ultra_ipi_rceive_ack);
|
|
audio_ipi_client_ultra_init();
|
|
return 0;
|
|
}
|
|
late_initcall(ultra_ipi_init);
|
|
|
|
MODULE_DESCRIPTION("Mediatek scp ultra platform driver");
|
|
MODULE_AUTHOR("Youwei Dong <Youwei.Dong@mediatek.com>");
|
|
MODULE_LICENSE("GPL v2");
|
|
|