162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (c) 2011 Samsung Electronics Co., Ltd
462306a36Sopenharmony_ci//		http://www.samsung.com
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <sound/soc.h>
862306a36Sopenharmony_ci#include <sound/pcm.h>
962306a36Sopenharmony_ci#include <sound/pcm_params.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "../codecs/wm8994.h"
1262306a36Sopenharmony_ci#include "pcm.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * Board Settings:
1662306a36Sopenharmony_ci *  o '1' means 'ON'
1762306a36Sopenharmony_ci *  o '0' means 'OFF'
1862306a36Sopenharmony_ci *  o 'X' means 'Don't care'
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * SMDKC210, SMDKV310: CFG3- 1001, CFG5-1000, CFG7-111111
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * Configure audio route as :-
2562306a36Sopenharmony_ci * $ amixer sset 'DAC1' on,on
2662306a36Sopenharmony_ci * $ amixer sset 'Right Headphone Mux' 'DAC'
2762306a36Sopenharmony_ci * $ amixer sset 'Left Headphone Mux' 'DAC'
2862306a36Sopenharmony_ci * $ amixer sset 'DAC1R Mixer AIF1.1' on
2962306a36Sopenharmony_ci * $ amixer sset 'DAC1L Mixer AIF1.1' on
3062306a36Sopenharmony_ci * $ amixer sset 'IN2L' on
3162306a36Sopenharmony_ci * $ amixer sset 'IN2L PGA IN2LN' on
3262306a36Sopenharmony_ci * $ amixer sset 'MIXINL IN2L' on
3362306a36Sopenharmony_ci * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on
3462306a36Sopenharmony_ci * $ amixer sset 'IN2R' on
3562306a36Sopenharmony_ci * $ amixer sset 'IN2R PGA IN2RN' on
3662306a36Sopenharmony_ci * $ amixer sset 'MIXINR IN2R' on
3762306a36Sopenharmony_ci * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* SMDK has a 16.9344MHZ crystal attached to WM8994 */
4162306a36Sopenharmony_ci#define SMDK_WM8994_FREQ 16934400
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream,
4462306a36Sopenharmony_ci			      struct snd_pcm_hw_params *params)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
4762306a36Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
4862306a36Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
4962306a36Sopenharmony_ci	unsigned long mclk_freq;
5062306a36Sopenharmony_ci	int rfs, ret;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	switch(params_rate(params)) {
5362306a36Sopenharmony_ci	case 8000:
5462306a36Sopenharmony_ci		rfs = 512;
5562306a36Sopenharmony_ci		break;
5662306a36Sopenharmony_ci	default:
5762306a36Sopenharmony_ci		dev_err(cpu_dai->dev, "%s:%d Sampling Rate %u not supported!\n",
5862306a36Sopenharmony_ci		__func__, __LINE__, params_rate(params));
5962306a36Sopenharmony_ci		return -EINVAL;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	mclk_freq = params_rate(params) * rfs;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
6562306a36Sopenharmony_ci					mclk_freq, SND_SOC_CLOCK_IN);
6662306a36Sopenharmony_ci	if (ret < 0)
6762306a36Sopenharmony_ci		return ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
7062306a36Sopenharmony_ci					SMDK_WM8994_FREQ, mclk_freq);
7162306a36Sopenharmony_ci	if (ret < 0)
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Set PCM source clock on CPU */
7562306a36Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
7662306a36Sopenharmony_ci					mclk_freq, SND_SOC_CLOCK_IN);
7762306a36Sopenharmony_ci	if (ret < 0)
7862306a36Sopenharmony_ci		return ret;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Set SCLK_DIV for making bclk */
8162306a36Sopenharmony_ci	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
8262306a36Sopenharmony_ci	if (ret < 0)
8362306a36Sopenharmony_ci		return ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const struct snd_soc_ops smdk_wm8994_pcm_ops = {
8962306a36Sopenharmony_ci	.hw_params = smdk_wm8994_pcm_hw_params,
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(paif_pcm,
9362306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("samsung-pcm.0")),
9462306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("wm8994-codec", "wm8994-aif1")),
9562306a36Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-pcm.0")));
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct snd_soc_dai_link smdk_dai[] = {
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		.name = "WM8994 PAIF PCM",
10062306a36Sopenharmony_ci		.stream_name = "Primary PCM",
10162306a36Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF |
10262306a36Sopenharmony_ci			   SND_SOC_DAIFMT_CBS_CFS,
10362306a36Sopenharmony_ci		.ops = &smdk_wm8994_pcm_ops,
10462306a36Sopenharmony_ci		SND_SOC_DAILINK_REG(paif_pcm),
10562306a36Sopenharmony_ci	},
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic struct snd_soc_card smdk_pcm = {
10962306a36Sopenharmony_ci	.name = "SMDK-PCM",
11062306a36Sopenharmony_ci	.owner = THIS_MODULE,
11162306a36Sopenharmony_ci	.dai_link = smdk_dai,
11262306a36Sopenharmony_ci	.num_links = 1,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int snd_smdk_probe(struct platform_device *pdev)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	int ret = 0;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	smdk_pcm.dev = &pdev->dev;
12062306a36Sopenharmony_ci	ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm);
12162306a36Sopenharmony_ci	if (ret)
12262306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return ret;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic struct platform_driver snd_smdk_driver = {
12862306a36Sopenharmony_ci	.driver = {
12962306a36Sopenharmony_ci		.name = "samsung-smdk-pcm",
13062306a36Sopenharmony_ci	},
13162306a36Sopenharmony_ci	.probe = snd_smdk_probe,
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cimodule_platform_driver(snd_smdk_driver);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ciMODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
13762306a36Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC SMDK WM8994 for PCM");
13862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
139