209 lines
7.1 KiB
C
209 lines
7.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Copyright (C) 2019 Cirrus Logic Inc.
|
|
*
|
|
*/
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* Filename:
|
|
* ---------
|
|
* mtk-cirrus-machine-ops.c
|
|
*
|
|
* Project:
|
|
* --------
|
|
* Audio soc machine vendor ops
|
|
*
|
|
* Description:
|
|
* ------------
|
|
* Audio machine driver
|
|
*
|
|
* Author:
|
|
* -------
|
|
* Vlad Karpovich
|
|
*
|
|
*------------------------------------------------------------------------------
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <sound/core.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-dapm.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <linux/atomic.h>
|
|
|
|
static atomic_t cs35l41_mclk_rsc_ref;
|
|
|
|
|
|
int cs35l41_snd_init(struct snd_soc_pcm_runtime *rtd)
|
|
{
|
|
struct snd_soc_card *card = rtd->card;
|
|
//struct snd_soc_codec *spk_cdc = rtd->codec_dais[0]->codec;
|
|
//struct snd_soc_dapm_context *spk_dapm = snd_soc_codec_get_dapm(spk_cdc);
|
|
//struct snd_soc_codec *rcv_cdc = rtd->codec_dais[1]->codec;
|
|
//struct snd_soc_dapm_context *rcv_dapm = snd_soc_codec_get_dapm(rcv_cdc);
|
|
|
|
//struct snd_soc_codec *spk1_cdc = rtd->codec_dais[0]->codec;
|
|
//struct snd_soc_dapm_context *spk1_dapm = snd_soc_codec_get_dapm(spk1_cdc);
|
|
//struct snd_soc_codec *spk2_cdc = rtd->codec_dais[1]->codec;
|
|
//struct snd_soc_dapm_context *spk2_dapm = snd_soc_codec_get_dapm(spk2_cdc);
|
|
|
|
//struct snd_soc_codec *spk3_cdc = rtd->codec_dais[2]->codec;
|
|
//struct snd_soc_dapm_context *spk3_dapm = snd_soc_codec_get_dapm(spk3_cdc);
|
|
//struct snd_soc_codec *spk4_cdc = rtd->codec_dais[3]->codec;
|
|
//struct snd_soc_dapm_context *spk4_dapm = snd_soc_codec_get_dapm(spk4_cdc);
|
|
|
|
|
|
//dev_info(card->dev, "%s: found codec[%s]\n", __func__, dev_name(spk1_cdc->dev));
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 AMP Playback");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 SPK");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 VMON ADC");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 AMP Capture");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 AMP Enable Switch");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 ASPRX1");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 ASPRX2");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 ASPRX3");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 ASPRX4");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK1 PCM Source");
|
|
//snd_soc_dapm_sync(spk1_dapm);
|
|
|
|
//dev_info(card->dev, "%s: found codec[%s]\n", __func__, dev_name(spk2_cdc->dev));
|
|
//snd_soc_dapm_ignore_suspend(spk2_dapm, "SPK2 AMP Playback");
|
|
//snd_soc_dapm_ignore_suspend(spk2_dapm, "SPK2 SPK");
|
|
//snd_soc_dapm_ignore_suspend(spk2_dapm, "SPK2 VMON ADC");
|
|
//snd_soc_dapm_ignore_suspend(spk2_dapm, "SPK2 AMP Capture");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 AMP Enable Switch");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 ASPRX1");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 ASPRX2");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 ASPRX3");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 ASPRX4");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK2 PCM Source");
|
|
//snd_soc_dapm_sync(spk2_dapm);
|
|
|
|
//dev_info(card->dev, "%s: found codec[%s]\n", __func__, dev_name(spk3_cdc->dev));
|
|
//snd_soc_dapm_ignore_suspend(spk3_dapm, "SPK3 AMP Playback");
|
|
//snd_soc_dapm_ignore_suspend(spk3_dapm, "SPK3 SPK");
|
|
//snd_soc_dapm_ignore_suspend(spk3_dapm, "SPK3 VMON ADC");
|
|
//snd_soc_dapm_ignore_suspend(spk3_dapm, "SPK3 AMP Capture");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 AMP Enable Switch");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 ASPRX1");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 ASPRX2");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 ASPRX3");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 ASPRX4");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK3 PCM Source");
|
|
//snd_soc_dapm_sync(spk3_dapm);
|
|
|
|
//dev_info(card->dev, "%s: found codec[%s]\n", __func__, dev_name(spk4_cdc->dev));
|
|
//snd_soc_dapm_ignore_suspend(spk4_dapm, "SPK4 AMP Playback");
|
|
//snd_soc_dapm_ignore_suspend(spk4_dapm, "SPK4 SPK");
|
|
//snd_soc_dapm_ignore_suspend(spk4_dapm, "SPK4 VMON ADC");
|
|
//snd_soc_dapm_ignore_suspend(spk4_dapm, "SPK4 AMP Capture");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 AMP Enable Switch");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 ASPRX1");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 ASPRX2");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 ASPRX3");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 ASPRX4");
|
|
//snd_soc_dapm_ignore_suspend(spk1_dapm, "SPK4 PCM Source");
|
|
//snd_soc_dapm_sync(spk4_dapm);
|
|
|
|
dev_info(card->dev, "%s: set cs35l43_mclk_rsc_ref to 0\n", __func__);
|
|
atomic_set(&cs35l41_mclk_rsc_ref, 0);
|
|
|
|
return 0;
|
|
}
|
|
static int cirrus_amp_startup(struct snd_pcm_substream *substream)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int cirrus_amp_hw_params(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *params)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
struct snd_soc_card *card = rtd->card;
|
|
struct snd_soc_dai **codec_dais = rtd->codec_dais;
|
|
int ret=0, i;
|
|
unsigned int clk_freq,rate;
|
|
//unsigned int slot_mask;
|
|
int slot_width = 32;
|
|
int slots = 4;
|
|
u8 asp_width;
|
|
|
|
asp_width = params_physical_width(params);
|
|
pr_info("%s\n cs35l43 width=%d", __func__, asp_width);
|
|
if (asp_width == 16)
|
|
slot_width = asp_width;
|
|
|
|
dev_info(card->dev, "+%s,cs35l43 mclk refcount = %d\n", __func__,
|
|
atomic_read(&cs35l41_mclk_rsc_ref));
|
|
|
|
if (atomic_inc_return(&cs35l41_mclk_rsc_ref) == 1) {
|
|
|
|
rate = params_rate(params);
|
|
clk_freq = rate * slot_width * slots;
|
|
|
|
for (i = 0; i < rtd->num_codecs; i++) {
|
|
//2 slot config - bits 0 and 1 set for the first two slots
|
|
// slot_mask = 0x0000FFFF >> (16 - slots);
|
|
|
|
// ret = snd_soc_dai_set_tdm_slot(codec_dais[i],
|
|
// 0, slot_mask,
|
|
// slots, slot_width);
|
|
// if (ret < 0) {
|
|
// dev_info(card->dev,"%s: cs35l43 failed to set tdm rx slot,
|
|
// err:%d\n", __func__, ret);
|
|
// return ret;
|
|
// }
|
|
|
|
ret = snd_soc_dai_set_fmt(codec_dais[i],
|
|
SND_SOC_DAIFMT_DSP_A |
|
|
SND_SOC_DAIFMT_CBS_CFS |
|
|
SND_SOC_DAIFMT_NB_NF);
|
|
if (ret != 0) {
|
|
dev_info(card->dev, "%s: cs35l43 Failed to set %s's fmt: ret = %d\n",
|
|
codec_dais[i]->name, ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = snd_soc_component_set_sysclk(codec_dais[i]->component,
|
|
0, 0,clk_freq,SND_SOC_CLOCK_IN);
|
|
if (ret < 0){
|
|
dev_info(card->dev," %s: cs35l43 set sysclk failed, err:%d\n",
|
|
codec_dais[i]->name, ret);
|
|
return ret ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void cirrus_amp_shutdown(struct snd_pcm_substream *substream)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
struct snd_soc_card *card = rtd->card;
|
|
|
|
dev_info(card->dev, "+%s, mclk refcount = %d\n", __func__,
|
|
atomic_read(&cs35l41_mclk_rsc_ref));
|
|
if (atomic_read(&cs35l41_mclk_rsc_ref) > 0) {
|
|
if (atomic_dec_return(&cs35l41_mclk_rsc_ref) == 0)
|
|
dev_info(card->dev, "-%s shutdown amp\n", __func__);
|
|
}
|
|
}
|
|
|
|
const struct snd_soc_ops cirrus_amp_ops = {
|
|
.startup = cirrus_amp_startup,
|
|
.hw_params = cirrus_amp_hw_params,
|
|
.shutdown = cirrus_amp_shutdown,
|
|
};
|
|
EXPORT_SYMBOL_GPL(cirrus_amp_ops);
|
|
|
|
|