brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · f52e250 Raw
688 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2020 Intel Corporation4 5#include <linux/device.h>6#include <linux/kernel.h>7#include <sound/pcm.h>8#include <sound/pcm_params.h>9#include <sound/soc.h>10#include <sound/soc-acpi.h>11#include <sound/soc-dai.h>12#include <sound/soc-dapm.h>13#include <sound/sof.h>14#include <uapi/sound/asound.h>15#include "../../codecs/rt1011.h"16#include "../../codecs/rt1015.h"17#include "../../codecs/rt1308.h"18#include "../common/soc-intel-quirks.h"19#include "sof_realtek_common.h"20 21/*22 * Common structures and functions23 */24static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = {25	SOC_DAPM_PIN_SWITCH("Left Spk"),26	SOC_DAPM_PIN_SWITCH("Right Spk"),27 28};29 30static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = {31	SND_SOC_DAPM_SPK("Left Spk", NULL),32	SND_SOC_DAPM_SPK("Right Spk", NULL),33};34 35static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = {36	SOC_DAPM_PIN_SWITCH("WL Ext Spk"),37	SOC_DAPM_PIN_SWITCH("WR Ext Spk"),38	SOC_DAPM_PIN_SWITCH("TL Ext Spk"),39	SOC_DAPM_PIN_SWITCH("TR Ext Spk"),40};41 42static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = {43	SND_SOC_DAPM_SPK("WL Ext Spk", NULL),44	SND_SOC_DAPM_SPK("WR Ext Spk", NULL),45	SND_SOC_DAPM_SPK("TL Ext Spk", NULL),46	SND_SOC_DAPM_SPK("TR Ext Spk", NULL),47};48 49/* helper function to get the number of specific codec */50static unsigned int get_num_codecs(const char *hid)51{52	struct acpi_device *adev;53	unsigned int dev_num = 0;54 55	for_each_acpi_dev_match(adev, hid, NULL, -1)56		dev_num++;57 58	return dev_num;59}60 61/*62 * Realtek ALC101163 */64static const struct snd_soc_dapm_route speaker_map_lr[] = {65	/* speaker */66	{ "Left Spk", NULL, "Left SPO" },67	{ "Right Spk", NULL, "Right SPO" },68};69 70static const struct snd_soc_dapm_route rt1011_4spk_routes[] = {71	{"WL Ext Spk", NULL, "WL SPO" },72	{"WR Ext Spk", NULL, "WR SPO" },73	{"TL Ext Spk", NULL, "TL SPO" },74	{"TR Ext Spk", NULL, "TR SPO" },75};76 77static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = {78	{79		.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),80		.name_prefix = "Left",81	},82	{83		.dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),84		.name_prefix = "Right",85	},86};87 88static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = {89	{90		.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),91		.name_prefix = "WL",92	},93	{94		.dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),95		.name_prefix = "WR",96	},97	{98		.dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME),99		.name_prefix = "TL",100	},101	{102		.dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME),103		.name_prefix = "TR",104	},105};106 107static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {108	{109		.name = RT1011_DEV0_NAME,110		.dai_name = RT1011_CODEC_DAI,111	},112	{113		.name = RT1011_DEV1_NAME,114		.dai_name = RT1011_CODEC_DAI,115	},116	{117		.name = RT1011_DEV2_NAME,118		.dai_name = RT1011_CODEC_DAI,119	},120	{121		.name = RT1011_DEV3_NAME,122		.dai_name = RT1011_CODEC_DAI,123	},124};125 126static const struct {127	unsigned int tx;128	unsigned int rx;129} rt1011_tdm_mask[] = {130	{.tx = 0x4, .rx = 0x1},131	{.tx = 0x8, .rx = 0x2},132	{.tx = 0x1, .rx = 0x1},133	{.tx = 0x2, .rx = 0x2},134};135 136static int rt1011_hw_params(struct snd_pcm_substream *substream,137			    struct snd_pcm_hw_params *params)138{139	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);140	struct snd_soc_dai *codec_dai;141	int srate, i, ret = 0;142 143	srate = params_rate(params);144 145	for_each_rtd_codec_dais(rtd, i, codec_dai) {146		/* 100 Fs to drive 24 bit data */147		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,148					  100 * srate, 256 * srate);149		if (ret < 0) {150			dev_err(codec_dai->dev, "fail to set pll, ret %d\n",151				ret);152			return ret;153		}154 155		ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,156					     256 * srate, SND_SOC_CLOCK_IN);157		if (ret < 0) {158			dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",159				ret);160			return ret;161		}162 163		if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {164			dev_err(codec_dai->dev, "invalid codec index %d\n",165				i);166			return -ENODEV;167		}168 169		ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,170					       rt1011_tdm_mask[i].rx, 4,171					       params_width(params));172		if (ret < 0) {173			dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",174				ret);175			return ret;176		}177	}178 179	return 0;180}181 182static const struct snd_soc_ops rt1011_ops = {183	.hw_params = rt1011_hw_params,184};185 186static int rt1011_init(struct snd_soc_pcm_runtime *rtd)187{188	struct snd_soc_card *card = rtd->card;189	unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);190	int ret;191 192	switch (num_codecs) {193	case 2:194		if (!soc_intel_is_cml()) {195			ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,196							ARRAY_SIZE(realtek_2spk_widgets));197			if (ret) {198				dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",199					ret);200				return ret;201			}202 203			ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,204							ARRAY_SIZE(realtek_2spk_kcontrols));205			if (ret) {206				dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n",207					ret);208				return ret;209			}210 211			ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr,212						      ARRAY_SIZE(speaker_map_lr));213			if (ret) {214				dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",215					ret);216				return ret;217			}218 219			break;220		}221 222		/*223		 * register speaker widgets "WL Ext Spk" and "WR Ext Spk" to224		 * keep backward compatible with cml devices225		 */226		fallthrough;227	case 4:228		ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets,229						num_codecs);230		if (ret) {231			dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",232				ret);233			return ret;234		}235 236		ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols,237						num_codecs);238		if (ret) {239			dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n",240				ret);241			return ret;242		}243 244		ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes,245					      num_codecs);246		if (ret) {247			dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",248				ret);249			return ret;250		}251		break;252	default:253		dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs);254		return -EINVAL;255	}256 257	return ret;258}259 260void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link)261{262	unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);263 264	link->codecs = rt1011_dai_link_components;265 266	switch (num_codecs) {267	case 2:268	case 4:269		link->num_codecs = num_codecs;270		break;271	default:272		dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);273		break;274	}275 276	link->init = rt1011_init;277	link->ops = &rt1011_ops;278}279EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);280 281void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card)282{283	unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);284 285	switch (num_codecs) {286	case 2:287		if (soc_intel_is_cml()) {288			/*289			 * use name prefix 'WL' and 'WR' for speaker widgets to290			 * keep backward compatible with cml devices291			 */292			card->codec_conf = rt1011_4spk_codec_confs;293		} else {294			card->codec_conf = rt1011_2spk_codec_confs;295		}296 297		card->num_configs = num_codecs;298		break;299	case 4:300		card->codec_conf = rt1011_4spk_codec_confs;301		card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs);302		break;303	default:304		dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);305		break;306	}307 308}309EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);310 311/*312 * rt1015:  i2c mode driver for ALC1015 and ALC1015Q313 * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB314 *315 * For stereo output, there are always two amplifiers on the board.316 * However, the ACPI implements only one device instance (UID=0) if they317 * are sharing the same enable pin. This is the case of rt1015p.318 */319static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {320	/* speaker */321	{ "Left Spk", NULL, "Speaker" },322	{ "Right Spk", NULL, "Speaker" },323};324 325static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {326	{327		.name = RT1015P_DEV0_NAME,328		.dai_name = RT1015P_CODEC_DAI,329	},330};331 332static int rt1015p_hw_params(struct snd_pcm_substream *substream,333			     struct snd_pcm_hw_params *params)334{335	/* reserved for debugging purpose */336 337	return 0;338}339 340static const struct snd_soc_ops rt1015p_ops = {341	.hw_params = rt1015p_hw_params,342};343 344static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)345{346	struct snd_soc_card *card = rtd->card;347	int ret;348 349	ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,350					ARRAY_SIZE(realtek_2spk_widgets));351	if (ret) {352		dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret);353		return ret;354	}355 356	ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,357					ARRAY_SIZE(realtek_2spk_kcontrols));358	if (ret) {359		dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret);360		return ret;361	}362 363	ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes,364				      ARRAY_SIZE(rt1015p_dapm_routes));365	if (ret)366		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);367	return ret;368}369 370void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)371{372	link->codecs = rt1015p_dai_link_components;373	link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components);374	link->init = rt1015p_init;375	link->ops = &rt1015p_ops;376}377EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);378 379void sof_rt1015p_codec_conf(struct snd_soc_card *card)380{381}382EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);383 384/*385 * RT1015 audio amplifier386 */387 388static const struct {389	unsigned int tx;390	unsigned int rx;391} rt1015_tdm_mask[] = {392	{.tx = 0x0, .rx = 0x1},393	{.tx = 0x0, .rx = 0x2},394};395 396static int rt1015_hw_params(struct snd_pcm_substream *substream,397			    struct snd_pcm_hw_params *params)398{399	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);400	struct snd_soc_dai_link *dai_link = rtd->dai_link;401	struct snd_soc_dai *codec_dai;402	int i, clk_freq;403	int ret = 0;404 405	clk_freq = sof_dai_get_bclk(rtd);406 407	if (clk_freq <= 0) {408		dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq);409		return -EINVAL;410	}411 412	for_each_rtd_codec_dais(rtd, i, codec_dai) {413		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,414					  clk_freq,415					  params_rate(params) * 256);416		if (ret) {417			dev_err(codec_dai->dev, "fail to set pll, ret %d\n",418				ret);419			return ret;420		}421 422		ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,423					     params_rate(params) * 256,424					     SND_SOC_CLOCK_IN);425		if (ret) {426			dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",427				ret);428			return ret;429		}430 431		switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {432		case SND_SOC_DAIFMT_DSP_A:433		case SND_SOC_DAIFMT_DSP_B:434			/* 4-slot TDM */435			ret = snd_soc_dai_set_tdm_slot(codec_dai,436						       rt1015_tdm_mask[i].tx,437						       rt1015_tdm_mask[i].rx,438						       4,439						       params_width(params));440			if (ret < 0) {441				dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",442					ret);443				return ret;444			}445			break;446		default:447			dev_dbg(codec_dai->dev, "codec is in I2S mode\n");448			break;449		}450	}451 452	return ret;453}454 455static const struct snd_soc_ops rt1015_ops = {456	.hw_params = rt1015_hw_params,457};458 459static struct snd_soc_codec_conf rt1015_amp_conf[] = {460	{461		.dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),462		.name_prefix = "Left",463	},464	{465		.dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),466		.name_prefix = "Right",467	},468};469 470static struct snd_soc_dai_link_component rt1015_components[] = {471	{472		.name = RT1015_DEV0_NAME,473		.dai_name = RT1015_CODEC_DAI,474	},475	{476		.name = RT1015_DEV1_NAME,477		.dai_name = RT1015_CODEC_DAI,478	},479};480 481static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd)482{483	struct snd_soc_card *card = rtd->card;484	unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID);485	int ret;486 487	switch (num_codecs) {488	case 2:489		ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,490						ARRAY_SIZE(realtek_2spk_widgets));491		if (ret) {492			dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n",493				ret);494			return ret;495		}496 497		ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,498						ARRAY_SIZE(realtek_2spk_kcontrols));499		if (ret) {500			dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n",501				ret);502			return ret;503		}504 505		ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr,506					      ARRAY_SIZE(speaker_map_lr));507		if (ret) {508			dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n",509				ret);510			return ret;511		}512		break;513	default:514		dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs);515		return -EINVAL;516	}517 518	return ret;519}520 521void sof_rt1015_codec_conf(struct snd_soc_card *card)522{523	card->codec_conf = rt1015_amp_conf;524	card->num_configs = ARRAY_SIZE(rt1015_amp_conf);525}526EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);527 528void sof_rt1015_dai_link(struct snd_soc_dai_link *link)529{530	link->codecs = rt1015_components;531	link->num_codecs = ARRAY_SIZE(rt1015_components);532	link->init = speaker_codec_init_lr;533	link->ops = &rt1015_ops;534}535EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);536 537/*538 * RT1308 audio amplifier539 */540static const struct snd_kcontrol_new rt1308_kcontrols[] = {541	SOC_DAPM_PIN_SWITCH("Speakers"),542};543 544static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = {545	SND_SOC_DAPM_SPK("Speakers", NULL),546};547 548static const struct snd_soc_dapm_route rt1308_dapm_routes[] = {549	/* speaker */550	{"Speakers", NULL, "SPOL"},551	{"Speakers", NULL, "SPOR"},552};553 554static struct snd_soc_dai_link_component rt1308_components[] = {555	{556		.name = RT1308_DEV0_NAME,557		.dai_name = RT1308_CODEC_DAI,558	}559};560 561static int rt1308_init(struct snd_soc_pcm_runtime *rtd)562{563	struct snd_soc_card *card = rtd->card;564	int ret;565 566	ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets,567					ARRAY_SIZE(rt1308_dapm_widgets));568	if (ret) {569		dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);570		return ret;571	}572 573	ret = snd_soc_add_card_controls(card, rt1308_kcontrols,574					ARRAY_SIZE(rt1308_kcontrols));575	if (ret) {576		dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret);577		return ret;578	}579 580	ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes,581				      ARRAY_SIZE(rt1308_dapm_routes));582 583	if (ret)584		dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret);585 586	return ret;587}588 589static int rt1308_hw_params(struct snd_pcm_substream *substream,590			    struct snd_pcm_hw_params *params)591{592	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);593	struct snd_soc_card *card = rtd->card;594	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);595	int clk_id, clk_freq, pll_out;596	int ret;597 598	clk_id = RT1308_PLL_S_MCLK;599	/* get the tplg configured mclk. */600	clk_freq = sof_dai_get_mclk(rtd);601 602	pll_out = params_rate(params) * 512;603 604	/* Set rt1308 pll */605	ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);606	if (ret < 0) {607		dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret);608		return ret;609	}610 611	/* Set rt1308 sysclk */612	ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,613				     SND_SOC_CLOCK_IN);614	if (ret < 0)615		dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret);616 617	return ret;618}619 620static const struct snd_soc_ops rt1308_ops = {621	.hw_params = rt1308_hw_params,622};623 624void sof_rt1308_dai_link(struct snd_soc_dai_link *link)625{626	link->codecs = rt1308_components;627	link->num_codecs = ARRAY_SIZE(rt1308_components);628	link->init = rt1308_init;629	link->ops = &rt1308_ops;630}631EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);632 633/*634 * 2-amp Configuration for RT1019635 */636 637static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {638	/* speaker */639	{ "Left Spk", NULL, "Speaker" },640	{ "Right Spk", NULL, "Speaker" },641};642 643static struct snd_soc_dai_link_component rt1019p_components[] = {644	{645		.name = RT1019P_DEV0_NAME,646		.dai_name = RT1019P_CODEC_DAI,647	},648};649 650static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)651{652	struct snd_soc_card *card = rtd->card;653	int ret;654 655	ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,656					ARRAY_SIZE(realtek_2spk_widgets));657	if (ret) {658		dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret);659		return ret;660	}661 662	ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,663					ARRAY_SIZE(realtek_2spk_kcontrols));664	if (ret) {665		dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret);666		return ret;667	}668 669	ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,670				      ARRAY_SIZE(rt1019p_dapm_routes));671	if (ret) {672		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);673		return ret;674	}675	return ret;676}677 678void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)679{680	link->codecs = rt1019p_components;681	link->num_codecs = ARRAY_SIZE(rt1019p_components);682	link->init = rt1019p_init;683}684EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);685 686MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");687MODULE_LICENSE("GPL");688