Path: blob/master/sound/soc/intel/boards/sof_realtek_common.c
26493 views
// SPDX-License-Identifier: GPL-2.0-only1//2// Copyright(c) 2020 Intel Corporation34#include <linux/device.h>5#include <linux/kernel.h>6#include <sound/pcm.h>7#include <sound/pcm_params.h>8#include <sound/soc.h>9#include <sound/soc-acpi.h>10#include <sound/soc-dai.h>11#include <sound/soc-dapm.h>12#include <sound/sof.h>13#include <uapi/sound/asound.h>14#include "../../codecs/rt1011.h"15#include "../../codecs/rt1015.h"16#include "../../codecs/rt1308.h"17#include "../common/soc-intel-quirks.h"18#include "sof_realtek_common.h"1920/*21* Common structures and functions22*/23static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = {24SOC_DAPM_PIN_SWITCH("Left Spk"),25SOC_DAPM_PIN_SWITCH("Right Spk"),2627};2829static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = {30SND_SOC_DAPM_SPK("Left Spk", NULL),31SND_SOC_DAPM_SPK("Right Spk", NULL),32};3334static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = {35SOC_DAPM_PIN_SWITCH("WL Ext Spk"),36SOC_DAPM_PIN_SWITCH("WR Ext Spk"),37SOC_DAPM_PIN_SWITCH("TL Ext Spk"),38SOC_DAPM_PIN_SWITCH("TR Ext Spk"),39};4041static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = {42SND_SOC_DAPM_SPK("WL Ext Spk", NULL),43SND_SOC_DAPM_SPK("WR Ext Spk", NULL),44SND_SOC_DAPM_SPK("TL Ext Spk", NULL),45SND_SOC_DAPM_SPK("TR Ext Spk", NULL),46};4748/* helper function to get the number of specific codec */49static unsigned int get_num_codecs(const char *hid)50{51struct acpi_device *adev;52unsigned int dev_num = 0;5354for_each_acpi_dev_match(adev, hid, NULL, -1)55dev_num++;5657return dev_num;58}5960/*61* Realtek ALC101162*/63static const struct snd_soc_dapm_route speaker_map_lr[] = {64/* speaker */65{ "Left Spk", NULL, "Left SPO" },66{ "Right Spk", NULL, "Right SPO" },67};6869static const struct snd_soc_dapm_route rt1011_4spk_routes[] = {70{"WL Ext Spk", NULL, "WL SPO" },71{"WR Ext Spk", NULL, "WR SPO" },72{"TL Ext Spk", NULL, "TL SPO" },73{"TR Ext Spk", NULL, "TR SPO" },74};7576static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = {77{78.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),79.name_prefix = "Left",80},81{82.dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),83.name_prefix = "Right",84},85};8687static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = {88{89.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),90.name_prefix = "WL",91},92{93.dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),94.name_prefix = "WR",95},96{97.dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME),98.name_prefix = "TL",99},100{101.dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME),102.name_prefix = "TR",103},104};105106static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {107{108.name = RT1011_DEV0_NAME,109.dai_name = RT1011_CODEC_DAI,110},111{112.name = RT1011_DEV1_NAME,113.dai_name = RT1011_CODEC_DAI,114},115{116.name = RT1011_DEV2_NAME,117.dai_name = RT1011_CODEC_DAI,118},119{120.name = RT1011_DEV3_NAME,121.dai_name = RT1011_CODEC_DAI,122},123};124125static const struct {126unsigned int tx;127unsigned int rx;128} rt1011_tdm_mask[] = {129{.tx = 0x4, .rx = 0x1},130{.tx = 0x8, .rx = 0x2},131{.tx = 0x1, .rx = 0x1},132{.tx = 0x2, .rx = 0x2},133};134135static int rt1011_hw_params(struct snd_pcm_substream *substream,136struct snd_pcm_hw_params *params)137{138struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);139struct snd_soc_dai *codec_dai;140int srate, i, ret = 0;141142srate = params_rate(params);143144for_each_rtd_codec_dais(rtd, i, codec_dai) {145/* 100 Fs to drive 24 bit data */146ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,147100 * srate, 256 * srate);148if (ret < 0) {149dev_err(codec_dai->dev, "fail to set pll, ret %d\n",150ret);151return ret;152}153154ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1,155256 * srate, SND_SOC_CLOCK_IN);156if (ret < 0) {157dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",158ret);159return ret;160}161162if (i >= ARRAY_SIZE(rt1011_tdm_mask)) {163dev_err(codec_dai->dev, "invalid codec index %d\n",164i);165return -ENODEV;166}167168ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx,169rt1011_tdm_mask[i].rx, 4,170params_width(params));171if (ret < 0) {172dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",173ret);174return ret;175}176}177178return 0;179}180181static const struct snd_soc_ops rt1011_ops = {182.hw_params = rt1011_hw_params,183};184185static int rt1011_init(struct snd_soc_pcm_runtime *rtd)186{187struct snd_soc_card *card = rtd->card;188unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);189int ret;190191switch (num_codecs) {192case 2:193if (!soc_intel_is_cml()) {194ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,195ARRAY_SIZE(realtek_2spk_widgets));196if (ret) {197dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",198ret);199return ret;200}201202ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,203ARRAY_SIZE(realtek_2spk_kcontrols));204if (ret) {205dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n",206ret);207return ret;208}209210ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr,211ARRAY_SIZE(speaker_map_lr));212if (ret) {213dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",214ret);215return ret;216}217218break;219}220221/*222* register speaker widgets "WL Ext Spk" and "WR Ext Spk" to223* keep backward compatible with cml devices224*/225fallthrough;226case 4:227ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets,228num_codecs);229if (ret) {230dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",231ret);232return ret;233}234235ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols,236num_codecs);237if (ret) {238dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n",239ret);240return ret;241}242243ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes,244num_codecs);245if (ret) {246dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",247ret);248return ret;249}250break;251default:252dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs);253return -EINVAL;254}255256return ret;257}258259void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link)260{261unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);262263link->codecs = rt1011_dai_link_components;264265switch (num_codecs) {266case 2:267case 4:268link->num_codecs = num_codecs;269break;270default:271dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);272break;273}274275link->init = rt1011_init;276link->ops = &rt1011_ops;277}278EXPORT_SYMBOL_NS(sof_rt1011_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");279280void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card)281{282unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);283284switch (num_codecs) {285case 2:286if (soc_intel_is_cml()) {287/*288* use name prefix 'WL' and 'WR' for speaker widgets to289* keep backward compatible with cml devices290*/291card->codec_conf = rt1011_4spk_codec_confs;292} else {293card->codec_conf = rt1011_2spk_codec_confs;294}295296card->num_configs = num_codecs;297break;298case 4:299card->codec_conf = rt1011_4spk_codec_confs;300card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs);301break;302default:303dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);304break;305}306307}308EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");309310/*311* rt1015: i2c mode driver for ALC1015 and ALC1015Q312* rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB313*314* For stereo output, there are always two amplifiers on the board.315* However, the ACPI implements only one device instance (UID=0) if they316* are sharing the same enable pin. This is the case of rt1015p.317*/318static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {319/* speaker */320{ "Left Spk", NULL, "Speaker" },321{ "Right Spk", NULL, "Speaker" },322};323324static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {325{326.name = RT1015P_DEV0_NAME,327.dai_name = RT1015P_CODEC_DAI,328},329};330331static int rt1015p_hw_params(struct snd_pcm_substream *substream,332struct snd_pcm_hw_params *params)333{334/* reserved for debugging purpose */335336return 0;337}338339static const struct snd_soc_ops rt1015p_ops = {340.hw_params = rt1015p_hw_params,341};342343static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)344{345struct snd_soc_card *card = rtd->card;346int ret;347348ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,349ARRAY_SIZE(realtek_2spk_widgets));350if (ret) {351dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret);352return ret;353}354355ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,356ARRAY_SIZE(realtek_2spk_kcontrols));357if (ret) {358dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret);359return ret;360}361362ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes,363ARRAY_SIZE(rt1015p_dapm_routes));364if (ret)365dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);366return ret;367}368369void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)370{371link->codecs = rt1015p_dai_link_components;372link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components);373link->init = rt1015p_init;374link->ops = &rt1015p_ops;375}376EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");377378void sof_rt1015p_codec_conf(struct snd_soc_card *card)379{380}381EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");382383/*384* RT1015 audio amplifier385*/386387static const struct {388unsigned int tx;389unsigned int rx;390} rt1015_tdm_mask[] = {391{.tx = 0x0, .rx = 0x1},392{.tx = 0x0, .rx = 0x2},393};394395static int rt1015_hw_params(struct snd_pcm_substream *substream,396struct snd_pcm_hw_params *params)397{398struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);399struct snd_soc_dai_link *dai_link = rtd->dai_link;400struct snd_soc_dai *codec_dai;401int i, clk_freq;402int ret = 0;403404clk_freq = sof_dai_get_bclk(rtd);405406if (clk_freq <= 0) {407dev_err(rtd->dev, "fail to get bclk freq, ret %d\n", clk_freq);408return -EINVAL;409}410411for_each_rtd_codec_dais(rtd, i, codec_dai) {412ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK,413clk_freq,414params_rate(params) * 256);415if (ret) {416dev_err(codec_dai->dev, "fail to set pll, ret %d\n",417ret);418return ret;419}420421ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,422params_rate(params) * 256,423SND_SOC_CLOCK_IN);424if (ret) {425dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n",426ret);427return ret;428}429430switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {431case SND_SOC_DAIFMT_DSP_A:432case SND_SOC_DAIFMT_DSP_B:433/* 4-slot TDM */434ret = snd_soc_dai_set_tdm_slot(codec_dai,435rt1015_tdm_mask[i].tx,436rt1015_tdm_mask[i].rx,4374,438params_width(params));439if (ret < 0) {440dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",441ret);442return ret;443}444break;445default:446dev_dbg(codec_dai->dev, "codec is in I2S mode\n");447break;448}449}450451return ret;452}453454static const struct snd_soc_ops rt1015_ops = {455.hw_params = rt1015_hw_params,456};457458static struct snd_soc_codec_conf rt1015_amp_conf[] = {459{460.dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME),461.name_prefix = "Left",462},463{464.dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME),465.name_prefix = "Right",466},467};468469static struct snd_soc_dai_link_component rt1015_components[] = {470{471.name = RT1015_DEV0_NAME,472.dai_name = RT1015_CODEC_DAI,473},474{475.name = RT1015_DEV1_NAME,476.dai_name = RT1015_CODEC_DAI,477},478};479480static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd)481{482struct snd_soc_card *card = rtd->card;483unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID);484int ret;485486switch (num_codecs) {487case 2:488ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,489ARRAY_SIZE(realtek_2spk_widgets));490if (ret) {491dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n",492ret);493return ret;494}495496ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,497ARRAY_SIZE(realtek_2spk_kcontrols));498if (ret) {499dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n",500ret);501return ret;502}503504ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr,505ARRAY_SIZE(speaker_map_lr));506if (ret) {507dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n",508ret);509return ret;510}511break;512default:513dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs);514return -EINVAL;515}516517return ret;518}519520void sof_rt1015_codec_conf(struct snd_soc_card *card)521{522card->codec_conf = rt1015_amp_conf;523card->num_configs = ARRAY_SIZE(rt1015_amp_conf);524}525EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");526527void sof_rt1015_dai_link(struct snd_soc_dai_link *link)528{529link->codecs = rt1015_components;530link->num_codecs = ARRAY_SIZE(rt1015_components);531link->init = speaker_codec_init_lr;532link->ops = &rt1015_ops;533}534EXPORT_SYMBOL_NS(sof_rt1015_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");535536/*537* RT1308 audio amplifier538*/539static const struct snd_kcontrol_new rt1308_kcontrols[] = {540SOC_DAPM_PIN_SWITCH("Speakers"),541};542543static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = {544SND_SOC_DAPM_SPK("Speakers", NULL),545};546547static const struct snd_soc_dapm_route rt1308_dapm_routes[] = {548/* speaker */549{"Speakers", NULL, "SPOL"},550{"Speakers", NULL, "SPOR"},551};552553static struct snd_soc_dai_link_component rt1308_components[] = {554{555.name = RT1308_DEV0_NAME,556.dai_name = RT1308_CODEC_DAI,557}558};559560static int rt1308_init(struct snd_soc_pcm_runtime *rtd)561{562struct snd_soc_card *card = rtd->card;563int ret;564565ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets,566ARRAY_SIZE(rt1308_dapm_widgets));567if (ret) {568dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);569return ret;570}571572ret = snd_soc_add_card_controls(card, rt1308_kcontrols,573ARRAY_SIZE(rt1308_kcontrols));574if (ret) {575dev_err(rtd->dev, "fail to add card controls, ret %d\n", ret);576return ret;577}578579ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes,580ARRAY_SIZE(rt1308_dapm_routes));581582if (ret)583dev_err(rtd->dev, "fail to add dapm routes, ret %d\n", ret);584585return ret;586}587588static int rt1308_hw_params(struct snd_pcm_substream *substream,589struct snd_pcm_hw_params *params)590{591struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);592struct snd_soc_card *card = rtd->card;593struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);594int clk_id, clk_freq, pll_out;595int ret;596597clk_id = RT1308_PLL_S_MCLK;598/* get the tplg configured mclk. */599clk_freq = sof_dai_get_mclk(rtd);600601pll_out = params_rate(params) * 512;602603/* Set rt1308 pll */604ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);605if (ret < 0) {606dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", ret);607return ret;608}609610/* Set rt1308 sysclk */611ret = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,612SND_SOC_CLOCK_IN);613if (ret < 0)614dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", ret);615616return ret;617}618619static const struct snd_soc_ops rt1308_ops = {620.hw_params = rt1308_hw_params,621};622623void sof_rt1308_dai_link(struct snd_soc_dai_link *link)624{625link->codecs = rt1308_components;626link->num_codecs = ARRAY_SIZE(rt1308_components);627link->init = rt1308_init;628link->ops = &rt1308_ops;629}630EXPORT_SYMBOL_NS(sof_rt1308_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");631632/*633* 2-amp Configuration for RT1019634*/635636static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {637/* speaker */638{ "Left Spk", NULL, "Speaker" },639{ "Right Spk", NULL, "Speaker" },640};641642static struct snd_soc_dai_link_component rt1019p_components[] = {643{644.name = RT1019P_DEV0_NAME,645.dai_name = RT1019P_CODEC_DAI,646},647};648649static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)650{651struct snd_soc_card *card = rtd->card;652int ret;653654ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets,655ARRAY_SIZE(realtek_2spk_widgets));656if (ret) {657dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret);658return ret;659}660661ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,662ARRAY_SIZE(realtek_2spk_kcontrols));663if (ret) {664dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret);665return ret;666}667668ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,669ARRAY_SIZE(rt1019p_dapm_routes));670if (ret) {671dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);672return ret;673}674return ret;675}676677void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)678{679link->codecs = rt1019p_components;680link->num_codecs = ARRAY_SIZE(rt1019p_components);681link->init = rt1019p_init;682}683EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");684685MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");686MODULE_LICENSE("GPL");687688689