blob: 355e7db3a8b3e7d976222c2a5fc672beae183080 [file] [log] [blame]
/*
* sound/soc/amlogic/auge/earc.c
*
* Copyright (C) 2019 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* Audio External Input/Out drirver
* such as fratv, frhdmirx
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "ddr_mngr.h"
#include "earc_hw.h"
#define DRV_NAME "EARC"
struct earc {
struct aml_audio_controller *actrl;
struct device *dev;
struct clk *clk_rx_gate;
struct clk *clk_rx_cmdc;
struct clk *clk_rx_dmac;
struct clk *clk_rx_cmdc_srcpll;
struct clk *clk_rx_dmac_srcpll;
struct clk *clk_tx_gate;
struct clk *clk_tx_cmdc;
struct clk *clk_tx_dmac;
struct clk *clk_tx_cmdc_srcpll;
struct clk *clk_tx_dmac_srcpll;
struct toddr *tddr;
struct frddr *fddr;
int irq_rx_cmdc;
int irq_rx_dmac;
int irq_tx_cmdc;
int irq_tx_dmac;
int sysclk_freq;
};
#define PREALLOC_BUFFER_MAX (256 * 1024)
#define EARC_RATES (SNDRV_PCM_RATE_8000_192000)
#define EARC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_pcm_hardware earc_hardware = {
.info =
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_PAUSE,
.formats = EARC_FORMATS,
.period_bytes_min = 64,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 1024,
.buffer_bytes_max = 256 * 1024,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
.channels_max = 32,
};
static irqreturn_t earc_ddr_isr(int irq, void *devid)
{
struct snd_pcm_substream *substream =
(struct snd_pcm_substream *)devid;
if (!snd_pcm_running(substream))
return IRQ_HANDLED;
snd_pcm_period_elapsed(substream);
return IRQ_HANDLED;
}
static irqreturn_t earc_rx_cmdc_isr(int irq, void *devid)
{
return IRQ_HANDLED;
}
static irqreturn_t earc_rx_dmac_isr(int irq, void *devid)
{
return IRQ_HANDLED;
}
static irqreturn_t earc_tx_cmdc_isr(int irq, void *devid)
{
return IRQ_HANDLED;
}
static irqreturn_t earc_tx_dmac_isr(int irq, void *devid)
{
return IRQ_HANDLED;
}
static int earc_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct device *dev = rtd->platform->dev;
struct earc *p_earc;
int ret = 0;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
p_earc = (struct earc *)dev_get_drvdata(dev);
snd_soc_set_runtime_hwparams(substream, &earc_hardware);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
p_earc->fddr = aml_audio_register_frddr(dev,
p_earc->actrl,
earc_ddr_isr, substream);
if (p_earc->fddr == NULL) {
dev_err(dev, "failed to claim from ddr\n");
return -ENXIO;
}
if (p_earc->irq_tx_cmdc > 0) {
ret = request_irq(p_earc->irq_tx_cmdc,
earc_tx_cmdc_isr, 0, "tx_cmdc",
p_earc);
if (ret) {
dev_err(p_earc->dev, "failed to claim irq_tx_cmdc %u\n",
p_earc->irq_tx_cmdc);
return ret;
}
}
if (p_earc->irq_tx_dmac > 0) {
ret = request_irq(p_earc->irq_tx_dmac,
earc_tx_dmac_isr, 0, "tx_dmac",
p_earc);
if (ret) {
dev_err(p_earc->dev, "failed to claim irq_tx_dmac %u\n",
p_earc->irq_tx_dmac);
return ret;
}
}
} else {
p_earc->tddr = aml_audio_register_toddr(dev,
p_earc->actrl,
earc_ddr_isr, substream);
if (p_earc->tddr == NULL) {
dev_err(dev, "failed to claim to ddr\n");
return -ENXIO;
}
ret = request_irq(p_earc->irq_rx_cmdc,
earc_rx_cmdc_isr, 0, "rx_cmdc",
p_earc);
if (ret) {
dev_err(p_earc->dev, "failed to claim irq_rx_cmdc %u\n",
p_earc->irq_rx_cmdc);
return ret;
}
ret = request_irq(p_earc->irq_rx_dmac,
earc_rx_dmac_isr, 0, "rx_dmac",
p_earc);
if (ret) {
dev_err(p_earc->dev, "failed to claim rx_dmac %u\n",
p_earc->irq_rx_dmac);
return ret;
}
}
runtime->private_data = p_earc;
return 0;
}
static int earc_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct earc *p_earc = runtime->private_data;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
aml_audio_unregister_frddr(p_earc->dev, substream);
if (p_earc->irq_tx_cmdc > 0)
free_irq(p_earc->irq_tx_cmdc, p_earc);
if (p_earc->irq_tx_dmac > 0)
free_irq(p_earc->irq_tx_dmac, p_earc);
} else {
aml_audio_unregister_toddr(p_earc->dev, substream);
free_irq(p_earc->irq_rx_cmdc, p_earc);
free_irq(p_earc->irq_rx_dmac, p_earc);
}
runtime->private_data = NULL;
return 0;
}
static int earc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
static int earc_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_free_pages(substream);
return 0;
}
static int earc_trigger(struct snd_pcm_substream *substream, int cmd)
{
return 0;
}
static int earc_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct earc *p_earc = runtime->private_data;
unsigned int start_addr, end_addr, int_addr;
start_addr = runtime->dma_addr;
end_addr = start_addr + runtime->dma_bytes - 8;
int_addr = frames_to_bytes(runtime, runtime->period_size) / 8;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
struct frddr *fr = p_earc->fddr;
aml_frddr_set_buf(fr, start_addr, end_addr);
aml_frddr_set_intrpt(fr, int_addr);
} else {
struct toddr *to = p_earc->tddr;
aml_toddr_set_buf(to, start_addr, end_addr);
aml_toddr_set_intrpt(to, int_addr);
}
return 0;
}
static snd_pcm_uframes_t earc_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct earc *p_earc = runtime->private_data;
unsigned int addr, start_addr;
snd_pcm_uframes_t frames;
start_addr = runtime->dma_addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
addr = aml_frddr_get_position(p_earc->fddr);
else
addr = aml_toddr_get_position(p_earc->tddr);
frames = bytes_to_frames(runtime, addr - start_addr);
if (frames > runtime->buffer_size)
frames = 0;
return frames;
}
int earc_silence(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
char *ppos;
int n;
n = frames_to_bytes(runtime, count);
ppos = runtime->dma_area + frames_to_bytes(runtime, pos);
memset(ppos, 0, n);
return 0;
}
static int earc_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
return snd_pcm_lib_default_mmap(substream, vma);
}
static struct snd_pcm_ops earc_ops = {
.open = earc_open,
.close = earc_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = earc_hw_params,
.hw_free = earc_hw_free,
.prepare = earc_prepare,
.trigger = earc_trigger,
.pointer = earc_pointer,
.silence = earc_silence,
.mmap = earc_mmap,
};
static int earc_new(struct snd_soc_pcm_runtime *rtd)
{
return snd_pcm_lib_preallocate_pages_for_all(
rtd->pcm, SNDRV_DMA_TYPE_DEV,
rtd->card->snd_card->dev,
PREALLOC_BUFFER_MAX,
PREALLOC_BUFFER_MAX);
}
struct snd_soc_platform_driver earc_platform = {
.ops = &earc_ops,
.pcm_new = earc_new,
};
static int earc_dai_probe(struct snd_soc_dai *cpu_dai)
{
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
return 0;
}
static int earc_dai_remove(struct snd_soc_dai *cpu_dai)
{
return 0;
}
static int earc_dai_prepare(
struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int bit_depth = snd_pcm_format_width(runtime->format);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
struct frddr *fr = p_earc->fddr;
enum frddr_dest dst = frddr_src_get();
pr_info("%s Expected frddr dst:%s\n",
__func__,
frddr_src_get_str(dst));
aml_frddr_select_dst(fr, dst);
aml_frddr_set_fifos(fr, 0x40, 0x20);
} else {
struct toddr *to = p_earc->tddr;
unsigned int msb = 0, lsb = 0, toddr_type = 0;
unsigned int src = EARCRX_DMAC;
struct toddr_fmt fmt;
if (bit_depth == 32)
toddr_type = 3;
else if (bit_depth == 24)
toddr_type = 4;
else
toddr_type = 0;
pr_info("%s Expected toddr src:%s\n",
__func__,
toddr_src_get_str(src));
msb = 28 - 1;
if (bit_depth == 16)
lsb = 28 - bit_depth;
else
lsb = 4;
pr_info("%s m:%d, n:%d, toddr type:%d\n",
__func__, msb, lsb, toddr_type);
fmt.type = toddr_type;
fmt.msb = msb;
fmt.lsb = lsb;
fmt.endian = 0;
fmt.bit_depth = bit_depth;
fmt.ch_num = runtime->channels;
fmt.rate = runtime->rate;
aml_toddr_select_src(to, src);
aml_toddr_set_format(to, &fmt);
aml_toddr_set_fifos(to, 0x40);
earcrx_cmdc_init();
earcrx_dmac_init();
earc_arc_init();
}
return 0;
}
static int earc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev_info(substream->pcm->card->dev, "eARC/ARC TX enable\n");
aml_frddr_enable(p_earc->fddr, true);
} else {
dev_info(substream->pcm->card->dev, "eARC/ARC RX enable\n");
aml_toddr_enable(p_earc->tddr, true);
earc_rx_enable(true);
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev_info(substream->pcm->card->dev, "eARC/ARC TX disable\n");
aml_frddr_enable(p_earc->fddr, false);
} else {
dev_info(substream->pcm->card->dev, "eARC/ARC RX disable\n");
earc_rx_enable(false);
aml_toddr_enable(p_earc->tddr, false);
}
break;
default:
return -EINVAL;
}
return 0;
}
static int earc_dai_hw_params(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int rate = params_rate(params);
int ret = 0;
pr_info("%s:rate:%d, sysclk:%d\n",
__func__,
rate,
p_earc->sysclk_freq);
return ret;
}
static int earc_dai_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
pr_info("asoc earc_dai_set_fmt, %#x, %p\n", fmt, p_earc);
return 0;
}
static int earc_dai_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
p_earc->sysclk_freq = freq;
pr_info("earc_dai_set_sysclk, %d, %d, %d\n",
clk_id, freq, dir);
clk_set_rate(p_earc->clk_rx_cmdc, 10000000);
clk_set_rate(p_earc->clk_rx_dmac, 250000000);
pr_info("earc rx cmdc clk:%lu rx dmac clk:%lu\n",
clk_get_rate(p_earc->clk_rx_cmdc),
clk_get_rate(p_earc->clk_rx_dmac));
return 0;
}
static int earc_dai_startup(
struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
/* enable clock gate */
if (!IS_ERR(p_earc->clk_rx_gate)) {
ret = clk_prepare_enable(p_earc->clk_rx_gate);
if (ret) {
pr_err("Can't enable earc rx_gate: %d\n", ret);
goto err;
}
}
audiobus_update_bits(EE_AUDIO_CLK_GATE_EN1, 0x1 << 6, 0x1 << 6);
/* enable clock */
if (!IS_ERR(p_earc->clk_rx_cmdc)) {
ret = clk_prepare_enable(p_earc->clk_rx_cmdc);
if (ret) {
pr_err("Can't enable earc clk_rx_cmdc: %d\n", ret);
goto err;
}
}
if (!IS_ERR(p_earc->clk_rx_dmac)) {
ret = clk_prepare_enable(p_earc->clk_rx_dmac);
if (ret) {
pr_err("Can't enable earc clk_rx_dmac: %d\n", ret);
goto err;
}
}
if (!IS_ERR(p_earc->clk_tx_cmdc)) {
ret = clk_prepare_enable(p_earc->clk_tx_cmdc);
if (ret) {
pr_err("Can't enable earc clk_tx_cmdc: %d\n", ret);
goto err;
}
}
if (!IS_ERR(p_earc->clk_tx_dmac)) {
ret = clk_prepare_enable(p_earc->clk_tx_dmac);
if (ret) {
pr_err("Can't enable earc clk_tx_dmac: %d\n", ret);
goto err;
}
}
return 0;
err:
pr_err("failed enable clock\n");
return -EINVAL;
}
static void earc_dai_shutdown(
struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct earc *p_earc = snd_soc_dai_get_drvdata(cpu_dai);
/* disable clock and gate */
if (!IS_ERR(p_earc->clk_rx_cmdc))
clk_disable_unprepare(p_earc->clk_rx_cmdc);
if (!IS_ERR(p_earc->clk_rx_dmac))
clk_disable_unprepare(p_earc->clk_rx_dmac);
if (!IS_ERR(p_earc->clk_tx_cmdc))
clk_disable_unprepare(p_earc->clk_tx_cmdc);
if (!IS_ERR(p_earc->clk_tx_dmac))
clk_disable_unprepare(p_earc->clk_tx_dmac);
if (!IS_ERR(p_earc->clk_rx_gate))
clk_disable_unprepare(p_earc->clk_rx_gate);
audiobus_update_bits(EE_AUDIO_CLK_GATE_EN1, 0x1 << 6, 0x0 << 6);
}
static struct snd_soc_dai_ops earc_dai_ops = {
.prepare = earc_dai_prepare,
.trigger = earc_dai_trigger,
.hw_params = earc_dai_hw_params,
.set_fmt = earc_dai_set_fmt,
.set_sysclk = earc_dai_set_sysclk,
.startup = earc_dai_startup,
.shutdown = earc_dai_shutdown,
};
static struct snd_soc_dai_driver earc_dai[] = {
{
.name = "EARC/ARC",
.id = 0,
.probe = earc_dai_probe,
.remove = earc_dai_remove,
.playback = {
.channels_min = 1,
.channels_max = 32,
.rates = EARC_RATES,
.formats = EARC_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 32,
.rates = EARC_RATES,
.formats = EARC_FORMATS,
},
.ops = &earc_dai_ops,
},
};
static const struct snd_kcontrol_new earc_controls[] = {
};
static const struct snd_soc_component_driver earc_component = {
.controls = earc_controls,
.num_controls = ARRAY_SIZE(earc_controls),
.name = DRV_NAME,
};
static const struct of_device_id earc_device_id[] = {
{
.compatible = "amlogic, sm1-snd-earc",
},
{},
};
MODULE_DEVICE_TABLE(of, earc_device_id);
static int earc_platform_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device_node *node_prt = NULL;
struct platform_device *pdev_parent;
struct device *dev = &pdev->dev;
struct aml_audio_controller *actrl = NULL;
struct earc *p_earc = NULL;
int ret = 0;
p_earc = devm_kzalloc(dev, sizeof(struct earc), GFP_KERNEL);
if (!p_earc)
return -ENOMEM;
p_earc->dev = dev;
dev_set_drvdata(dev, p_earc);
/* get audio controller */
node_prt = of_get_parent(node);
if (node_prt == NULL)
return -ENXIO;
pdev_parent = of_find_device_by_node(node_prt);
of_node_put(node_prt);
actrl = (struct aml_audio_controller *)
platform_get_drvdata(pdev_parent);
p_earc->actrl = actrl;
/* clock gate */
p_earc->clk_rx_gate = devm_clk_get(&pdev->dev, "rx_gate");
if (IS_ERR(p_earc->clk_rx_gate)) {
dev_err(&pdev->dev,
"Can't get earc gate\n");
return PTR_ERR(p_earc->clk_rx_gate);
}
/* RX */
p_earc->clk_rx_cmdc = devm_clk_get(&pdev->dev, "rx_cmdc");
if (IS_ERR(p_earc->clk_rx_cmdc)) {
dev_err(&pdev->dev,
"Can't get clk_rx_cmdc\n");
return PTR_ERR(p_earc->clk_rx_cmdc);
}
p_earc->clk_rx_dmac = devm_clk_get(&pdev->dev, "rx_dmac");
if (IS_ERR(p_earc->clk_rx_dmac)) {
dev_err(&pdev->dev,
"Can't get clk_rx_dmac\n");
return PTR_ERR(p_earc->clk_rx_dmac);
}
p_earc->clk_rx_cmdc_srcpll = devm_clk_get(&pdev->dev, "rx_cmdc_srcpll");
if (IS_ERR(p_earc->clk_rx_cmdc_srcpll)) {
dev_err(&pdev->dev,
"Can't get clk_rx_cmdc_srcpll\n");
return PTR_ERR(p_earc->clk_rx_cmdc_srcpll);
}
p_earc->clk_rx_dmac_srcpll = devm_clk_get(&pdev->dev, "rx_dmac_srcpll");
if (IS_ERR(p_earc->clk_rx_dmac_srcpll)) {
dev_err(&pdev->dev,
"Can't get clk_rx_dmac_srcpll\n");
return PTR_ERR(p_earc->clk_rx_dmac_srcpll);
}
ret = clk_set_parent(p_earc->clk_rx_cmdc, p_earc->clk_rx_cmdc_srcpll);
if (ret) {
dev_err(dev,
"Can't set clk_rx_cmdc parent clock\n");
ret = PTR_ERR(p_earc->clk_rx_cmdc);
return ret;
}
ret = clk_set_parent(p_earc->clk_rx_dmac, p_earc->clk_rx_dmac_srcpll);
if (ret) {
dev_err(dev,
"Can't set clk_rx_dmac parent clock\n");
ret = PTR_ERR(p_earc->clk_rx_dmac);
return ret;
}
/* TX */
p_earc->clk_tx_cmdc = devm_clk_get(&pdev->dev, "tx_cmdc");
if (IS_ERR(p_earc->clk_tx_cmdc)) {
dev_err(&pdev->dev,
"Check whether support eARC TX\n");
}
p_earc->clk_tx_dmac = devm_clk_get(&pdev->dev, "tx_dmac");
if (IS_ERR(p_earc->clk_tx_dmac)) {
dev_err(&pdev->dev,
"Check whether support eARC TX\n");
}
p_earc->clk_tx_cmdc_srcpll = devm_clk_get(&pdev->dev, "tx_cmdc_srcpll");
if (IS_ERR(p_earc->clk_tx_cmdc_srcpll)) {
dev_err(&pdev->dev,
"Check whether support eARC TX\n");
}
p_earc->clk_tx_dmac_srcpll = devm_clk_get(&pdev->dev, "tx_dmac_srcpll");
if (IS_ERR(p_earc->clk_tx_dmac_srcpll)) {
dev_err(&pdev->dev,
"Check whether support eARC TX\n");
}
if (!IS_ERR(p_earc->clk_tx_cmdc) &&
!IS_ERR(p_earc->clk_tx_cmdc_srcpll)) {
ret = clk_set_parent(p_earc->clk_tx_cmdc,
p_earc->clk_tx_cmdc_srcpll);
if (ret) {
dev_err(dev,
"Can't set clk_tx_cmdc parent clock\n");
ret = PTR_ERR(p_earc->clk_tx_cmdc);
return ret;
}
}
if (!IS_ERR(p_earc->clk_tx_dmac) &&
!IS_ERR(p_earc->clk_tx_dmac_srcpll)) {
ret = clk_set_parent(p_earc->clk_tx_dmac,
p_earc->clk_tx_dmac_srcpll);
if (ret) {
dev_err(dev,
"Can't set clk_tx_dmac parent clock\n");
ret = PTR_ERR(p_earc->clk_tx_dmac);
return ret;
}
}
/* irqs */
p_earc->irq_rx_cmdc =
platform_get_irq_byname(pdev, "rx_cmdc");
if (p_earc->irq_rx_cmdc < 0) {
dev_err(dev, "platform get irq rx_cmdc failed\n");
return p_earc->irq_rx_cmdc;
}
p_earc->irq_rx_dmac =
platform_get_irq_byname(pdev, "rx_dmac");
if (p_earc->irq_rx_dmac < 0) {
dev_err(dev, "platform get irq rx_dmac failed\n");
return p_earc->irq_rx_dmac;
}
p_earc->irq_tx_cmdc =
platform_get_irq_byname(pdev, "tx_cmdc");
if (p_earc->irq_tx_cmdc < 0)
dev_err(dev, "platform get irq tx_cmdc failed, Check whether support eARC TX\n");
p_earc->irq_tx_dmac =
platform_get_irq_byname(pdev, "tx_dmac");
if (p_earc->irq_tx_dmac < 0)
dev_err(dev, "platform get irq tx_dmac failed, Check whether support eARC TX\n");
ret = snd_soc_register_component(&pdev->dev,
&earc_component,
earc_dai,
ARRAY_SIZE(earc_dai));
if (ret) {
dev_err(&pdev->dev,
"snd_soc_register_component failed\n");
return ret;
}
pr_info("%s, register soc platform\n", __func__);
return devm_snd_soc_register_platform(dev, &earc_platform);
}
struct platform_driver earc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = earc_device_id,
},
.probe = earc_platform_probe,
};
module_platform_driver(earc_driver);
MODULE_AUTHOR("Amlogic, Inc.");
MODULE_DESCRIPTION("Amlogic eARC/ARC TX/RX ASoc driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("Platform:" DRV_NAME);
MODULE_DEVICE_TABLE(of, earc_device_id);