1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-02-15 00:18:03 +00:00
a155-U-u1/kernel-5.10/sound/soc/mediatek/audio_scp/mtk-scp-audio-driver.c
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

193 lines
5.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2018 MediaTek Inc.
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "scp_audio_ipi.h"
#include "scp.h"
#include "mtk-scp-audio-base.h"
#include "mtk-scp-audio-pcm.h"
#include "mtk-scp-audio-mem-control.h"
#define SND_SCP_AUDIO_DTS_SIZE (4)
#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 |\
SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static struct mtk_scp_audio_base *local_scp_audio;
static const struct snd_pcm_hardware scp_audio_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = MTK_PCM_FORMATS,
.rates = MTK_PCM_RATES,
.period_bytes_min = 256,
.period_bytes_max = 4 * 48 * 1024,
.periods_min = 2,
.periods_max = 4096,
.buffer_bytes_max = 4 * 48 * 1024,
.fifo_size = 0,
};
int set_scp_audio_base(struct mtk_scp_audio_base *pScpAudio)
{
if (pScpAudio == NULL)
pr_info("%s pScpAudio == NULL", __func__);
local_scp_audio = pScpAudio;
return 0;
}
void *get_scp_audio_base(void)
{
if (local_scp_audio == NULL)
pr_warn("%s local_scp_audio == NULL", __func__);
return local_scp_audio;
}
EXPORT_SYMBOL(get_scp_audio_base);
/* user-space event notify */
static int scp_user_event_notify(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
struct device *dev = scp_audio->dev;
int ret = 0;
if (!dev)
return NOTIFY_DONE;
switch (event) {
case SCP_EVENT_STOP:
pr_info("%s(), SCP_EVENT_STOP\n", __func__);
ret = kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
break;
case SCP_EVENT_READY:
pr_info("%s(), SCP_EVENT_READY\n", __func__);
ret = kobject_uevent(&dev->kobj, KOBJ_ONLINE);
break;
default:
pr_info("%s, ignore event %lu", __func__, event);
break;
}
if (ret)
pr_info("%s, uevnet(%lu) fail, ret %d", __func__, event, ret);
return NOTIFY_OK;
}
struct notifier_block scp_uevent_notifier = {
.notifier_call = scp_user_event_notify,
};
static struct notifier_block scp_audio_recover_notifier = {
.notifier_call = scp_audio_pcm_recover_event,
};
static int scp_audio_dev_probe(struct platform_device *pdev)
{
struct mtk_scp_audio_base *scp_audio;
struct scp_audio_task_attr task_attr;
int ret = 0;
struct device *dev;
ret = of_property_read_u32_array(pdev->dev.of_node,
"scp_spk_process_enable",
(unsigned int *)&task_attr,
SND_SCP_AUDIO_DTS_SIZE);
if (ret != 0) {
pr_info("%s cannot get spkProcess attr\n", __func__);
init_scp_spk_process_enable(0);
} else {
pr_info("%s enable=0x%x, 0x%x 0x%x 0x%x\n", __func__,
task_attr.default_enable,
task_attr.dl_memif,
task_attr.ul_memif,
task_attr.ref_memif);
init_scp_spk_process_enable(task_attr.default_enable);
}
scp_audio = devm_kzalloc(&pdev->dev, sizeof(struct mtk_scp_audio_base),
GFP_KERNEL);
if (!scp_audio)
return -ENOMEM;
scp_audio->dl_memif = task_attr.dl_memif;
scp_audio->ul_memif = task_attr.ul_memif;
scp_audio->ref_memif = task_attr.ref_memif;
/* register scp audio dai driver*/
scp_audio_dai_register(pdev, scp_audio);
scp_audio->scp_audio_hardware = &scp_audio_hardware;
scp_audio->dev = &pdev->dev;
dev = scp_audio->dev;
scp_audio->request_dram_resource = scp_audio_dram_request;
scp_audio->release_dram_resource = scp_audio_dram_release;
scp_audio->ipi_ops.ipi_message_callback = scp_audio_pcm_ipi_recv;
scp_audio->ipi_ops.ipi_handler = scp_aud_ipi_handler;
platform_set_drvdata(pdev, scp_audio);
pm_runtime_enable(&pdev->dev);
set_scp_audio_base(scp_audio);
mtk_scp_audio_init_mem();
if (pdev->dev.of_node) {
dev_set_name(&pdev->dev, "%s", "snd_scp_audio");
pdev->name = pdev->dev.kobj.name;
pr_info("dev name %s\n", pdev->name);
}
ret = snd_soc_register_component(&pdev->dev,
&mtk_scp_audio_pcm_platform,
scp_audio->dai_drivers,
scp_audio->num_dai_drivers);
if (ret) {
dev_info(&pdev->dev, "%s() err_platform: %d\n", __func__, ret);
return -1;
}
scp_A_register_notify(&scp_audio_recover_notifier);
scp_A_register_notify(&scp_uevent_notifier);
pr_info("%s done, ret:%d\n", __func__, ret);
return 0;
}
static const struct of_device_id scp_audio_dt_match[] = {
{ .compatible = "mediatek,snd_scp_audio", },
{},
};
MODULE_DEVICE_TABLE(of, scp_audio_dt_match);
static struct platform_driver scp_audio_driver = {
.driver = {
.name = "snd_scp_audio",
.owner = THIS_MODULE,
.of_match_table = scp_audio_dt_match,
},
.probe = scp_audio_dev_probe,
};
module_platform_driver(scp_audio_driver);
MODULE_DESCRIPTION("Mediatek ALSA SoC platform driver for scp audio");
MODULE_AUTHOR("Zhixiong Wang <zhixiong.wang@mediatek.com>");
MODULE_LICENSE("GPL v2");