brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 9178bbe Raw
312 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  bytcht-da7213.c - ASoc Machine driver for Intel Baytrail and4 *             Cherrytrail-based platforms, with Dialog DA7213 codec5 *6 *  Copyright (C) 2017 Intel Corporation7 *  Author: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>8 *9 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~10 *11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~12 */13 14#include <linux/module.h>15#include <linux/acpi.h>16#include <linux/platform_device.h>17#include <linux/slab.h>18#include <sound/pcm.h>19#include <sound/pcm_params.h>20#include <sound/soc.h>21#include <sound/soc-acpi.h>22#include "../../codecs/da7213.h"23#include "../atom/sst-atom-controls.h"24 25static const struct snd_kcontrol_new controls[] = {26	SOC_DAPM_PIN_SWITCH("Headphone Jack"),27	SOC_DAPM_PIN_SWITCH("Headset Mic"),28	SOC_DAPM_PIN_SWITCH("Mic"),29	SOC_DAPM_PIN_SWITCH("Aux In"),30};31 32static const struct snd_soc_dapm_widget dapm_widgets[] = {33	SND_SOC_DAPM_HP("Headphone Jack", NULL),34	SND_SOC_DAPM_MIC("Headset Mic", NULL),35	SND_SOC_DAPM_MIC("Mic", NULL),36	SND_SOC_DAPM_LINE("Aux In", NULL),37};38 39static const struct snd_soc_dapm_route audio_map[] = {40	{"Headphone Jack", NULL, "HPL"},41	{"Headphone Jack", NULL, "HPR"},42 43	{"AUXL", NULL, "Aux In"},44	{"AUXR", NULL, "Aux In"},45 46	/* Assume Mic1 is linked to Headset and Mic2 to on-board mic */47	{"MIC1", NULL, "Headset Mic"},48	{"MIC2", NULL, "Mic"},49 50	/* SOC-codec link */51	{"ssp2 Tx", NULL, "codec_out0"},52	{"ssp2 Tx", NULL, "codec_out1"},53	{"codec_in0", NULL, "ssp2 Rx"},54	{"codec_in1", NULL, "ssp2 Rx"},55 56	{"Playback", NULL, "ssp2 Tx"},57	{"ssp2 Rx", NULL, "Capture"},58};59 60static int codec_fixup(struct snd_soc_pcm_runtime *rtd,61		       struct snd_pcm_hw_params *params)62{63	int ret;64	struct snd_interval *rate = hw_param_interval(params,65			SNDRV_PCM_HW_PARAM_RATE);66	struct snd_interval *channels = hw_param_interval(params,67						SNDRV_PCM_HW_PARAM_CHANNELS);68 69	/* The DSP will convert the FE rate to 48k, stereo, 24bits */70	rate->min = rate->max = 48000;71	channels->min = channels->max = 2;72 73	/* set SSP2 to 24-bit */74	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);75 76	/*77	 * Default mode for SSP configuration is TDM 4 slot, override config78	 * with explicit setting to I2S 2ch 24-bit. The word length is set with79	 * dai_set_tdm_slot() since there is no other API exposed80	 */81	ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),82				  SND_SOC_DAIFMT_I2S     |83				  SND_SOC_DAIFMT_NB_NF   |84				  SND_SOC_DAIFMT_BP_FP);85	if (ret < 0) {86		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);87		return ret;88	}89 90	ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);91	if (ret < 0) {92		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);93		return ret;94	}95 96	return 0;97}98 99static int aif1_startup(struct snd_pcm_substream *substream)100{101	return snd_pcm_hw_constraint_single(substream->runtime,102			SNDRV_PCM_HW_PARAM_RATE, 48000);103}104 105static int aif1_hw_params(struct snd_pcm_substream *substream,106			  struct snd_pcm_hw_params *params)107{108	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);109	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);110	int ret;111 112	ret = snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK,113				     19200000, SND_SOC_CLOCK_IN);114	if (ret < 0)115		dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");116 117	ret = snd_soc_dai_set_pll(codec_dai, 0,118			DA7213_SYSCLK_PLL_SRM, 0, DA7213_PLL_FREQ_OUT_98304000);119	if (ret < 0) {120		dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);121		return -EIO;122	}123 124	return ret;125}126 127static int aif1_hw_free(struct snd_pcm_substream *substream)128{129	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);130	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);131	int ret;132 133	ret = snd_soc_dai_set_pll(codec_dai, 0,134				  DA7213_SYSCLK_MCLK, 0, 0);135	if (ret < 0) {136		dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);137		return -EIO;138	}139 140	return ret;141}142 143static const struct snd_soc_ops aif1_ops = {144	.startup = aif1_startup,145};146 147static const struct snd_soc_ops ssp2_ops = {148	.hw_params = aif1_hw_params,149	.hw_free = aif1_hw_free,150 151};152 153SND_SOC_DAILINK_DEF(dummy,154	DAILINK_COMP_ARRAY(COMP_DUMMY()));155 156SND_SOC_DAILINK_DEF(media,157	DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));158 159SND_SOC_DAILINK_DEF(deepbuffer,160	DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));161 162SND_SOC_DAILINK_DEF(ssp2_port,163	DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));164SND_SOC_DAILINK_DEF(ssp2_codec,165	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7213:00",166				      "da7213-hifi")));167 168SND_SOC_DAILINK_DEF(platform,169	DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));170 171static struct snd_soc_dai_link dailink[] = {172	[MERR_DPCM_AUDIO] = {173		.name = "Audio Port",174		.stream_name = "Audio",175		.nonatomic = true,176		.dynamic = 1,177		.dpcm_playback = 1,178		.dpcm_capture = 1,179		.ops = &aif1_ops,180		SND_SOC_DAILINK_REG(media, dummy, platform),181	},182	[MERR_DPCM_DEEP_BUFFER] = {183		.name = "Deep-Buffer Audio Port",184		.stream_name = "Deep-Buffer Audio",185		.nonatomic = true,186		.dynamic = 1,187		.dpcm_playback = 1,188		.ops = &aif1_ops,189		SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),190	},191	/* CODEC<->CODEC link */192	/* back ends */193	{194		.name = "SSP2-Codec",195		.id = 0,196		.no_pcm = 1,197		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF198						| SND_SOC_DAIFMT_CBC_CFC,199		.be_hw_params_fixup = codec_fixup,200		.dpcm_playback = 1,201		.dpcm_capture = 1,202		.ops = &ssp2_ops,203		SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),204	},205};206 207/* use space before codec name to simplify card ID, and simplify driver name */208#define SOF_CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */209#define SOF_DRIVER_NAME "SOF"210 211#define CARD_NAME "bytcht-da7213"212#define DRIVER_NAME NULL /* card name will be used for driver name */213 214/* SoC card */215static struct snd_soc_card bytcht_da7213_card = {216	.name = CARD_NAME,217	.driver_name = DRIVER_NAME,218	.owner = THIS_MODULE,219	.dai_link = dailink,220	.num_links = ARRAY_SIZE(dailink),221	.controls = controls,222	.num_controls = ARRAY_SIZE(controls),223	.dapm_widgets = dapm_widgets,224	.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),225	.dapm_routes = audio_map,226	.num_dapm_routes = ARRAY_SIZE(audio_map),227};228 229static char codec_name[SND_ACPI_I2C_ID_LEN];230 231static int bytcht_da7213_probe(struct platform_device *pdev)232{233	struct snd_soc_card *card;234	struct snd_soc_acpi_mach *mach;235	const char *platform_name;236	struct acpi_device *adev;237	bool sof_parent;238	int dai_index = 0;239	int ret_val = 0;240	int i;241 242	mach = pdev->dev.platform_data;243	card = &bytcht_da7213_card;244	card->dev = &pdev->dev;245 246	/* fix index of codec dai */247	for (i = 0; i < ARRAY_SIZE(dailink); i++) {248		if (dailink[i].num_codecs &&249		    !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {250			dai_index = i;251			break;252		}253	}254 255	/* fixup codec name based on HID */256	adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);257	if (adev) {258		snprintf(codec_name, sizeof(codec_name),259			 "i2c-%s", acpi_dev_name(adev));260		dailink[dai_index].codecs->name = codec_name;261	} else {262		dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);263		return -ENOENT;264	}265 266	acpi_dev_put(adev);267 268	/* override platform name, if required */269	platform_name = mach->mach_params.platform;270 271	ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name);272	if (ret_val)273		return ret_val;274 275	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);276 277	/* set card and driver name */278	if (sof_parent) {279		bytcht_da7213_card.name = SOF_CARD_NAME;280		bytcht_da7213_card.driver_name = SOF_DRIVER_NAME;281	} else {282		bytcht_da7213_card.name = CARD_NAME;283		bytcht_da7213_card.driver_name = DRIVER_NAME;284	}285 286	/* set pm ops */287	if (sof_parent)288		pdev->dev.driver->pm = &snd_soc_pm_ops;289 290	ret_val = devm_snd_soc_register_card(&pdev->dev, card);291	if (ret_val) {292		dev_err(&pdev->dev,293			"snd_soc_register_card failed %d\n", ret_val);294		return ret_val;295	}296	platform_set_drvdata(pdev, card);297	return ret_val;298}299 300static struct platform_driver bytcht_da7213_driver = {301	.driver = {302		.name = "bytcht_da7213",303	},304	.probe = bytcht_da7213_probe,305};306module_platform_driver(bytcht_da7213_driver);307 308MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail+DA7213 Machine driver");309MODULE_AUTHOR("Pierre-Louis Bossart");310MODULE_LICENSE("GPL v2");311MODULE_ALIAS("platform:bytcht_da7213");312