brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 230af8d Raw
462 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.4//5// ALSA SoC Machine driver for sc72806 7#include <dt-bindings/sound/qcom,lpass.h>8#include <dt-bindings/sound/qcom,q6afe.h>9#include <linux/input.h>10#include <linux/mod_devicetable.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <sound/core.h>14#include <sound/jack.h>15#include <sound/pcm.h>16#include <sound/soc.h>17#include <sound/rt5682s.h>18#include <linux/soundwire/sdw.h>19#include <sound/pcm_params.h>20 21#include "../codecs/rt5682.h"22#include "../codecs/rt5682s.h"23#include "common.h"24#include "lpass.h"25#include "qdsp6/q6afe.h"26#include "sdw.h"27 28#define DEFAULT_MCLK_RATE              1920000029#define RT5682_PLL_FREQ (48000 * 512)30#define MI2S_BCLK_RATE		153600031 32struct sc7280_snd_data {33	struct snd_soc_card card;34	struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS];35	u32 pri_mi2s_clk_count;36	struct snd_soc_jack hs_jack;37	struct snd_soc_jack hdmi_jack;38	bool jack_setup;39	bool stream_prepared[LPASS_MAX_PORTS];40};41 42static void sc7280_jack_free(struct snd_jack *jack)43{44	struct snd_soc_component *component = jack->private_data;45 46	snd_soc_component_set_jack(component, NULL, NULL);47}48 49static struct snd_soc_jack_pin sc7280_jack_pins[] = {50	{51		.pin = "Headphone Jack",52		.mask = SND_JACK_HEADPHONE,53	},54	{55		.pin = "Headset Mic",56		.mask = SND_JACK_MICROPHONE,57	},58};59 60static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)61{62	struct snd_soc_card *card = rtd->card;63	struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);64	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);65	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);66	struct snd_soc_component *component = codec_dai->component;67	struct snd_jack *jack;68	int rval, i;69 70	if (!pdata->jack_setup) {71		rval = snd_soc_card_jack_new_pins(card, "Headset Jack",72						  SND_JACK_HEADSET | SND_JACK_LINEOUT |73						  SND_JACK_MECHANICAL |74						  SND_JACK_BTN_0 | SND_JACK_BTN_1 |75						  SND_JACK_BTN_2 | SND_JACK_BTN_3 |76						  SND_JACK_BTN_4 | SND_JACK_BTN_5,77						  &pdata->hs_jack,78						  sc7280_jack_pins,79						  ARRAY_SIZE(sc7280_jack_pins));80 81		if (rval < 0) {82			dev_err(card->dev, "Unable to add Headset Jack\n");83			return rval;84		}85 86		jack = pdata->hs_jack.jack;87 88		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);89		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);90		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);91		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);92 93		jack->private_data = component;94		jack->private_free = sc7280_jack_free;95		pdata->jack_setup = true;96	}97	switch (cpu_dai->id) {98	case MI2S_PRIMARY:99	case LPASS_CDC_DMA_RX0:100	case LPASS_CDC_DMA_TX3:101	case TX_CODEC_DMA_TX_3:102		for_each_rtd_codec_dais(rtd, i, codec_dai) {103			rval = snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);104			if (rval != 0 && rval != -ENOTSUPP) {105				dev_err(card->dev, "Failed to set jack: %d\n", rval);106				return rval;107			}108		}109		break;110	default:111		break;112	}113 114	return 0;115}116 117static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)118{119	struct snd_soc_card *card = rtd->card;120	struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);121	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);122	struct snd_soc_component *component = codec_dai->component;123	struct snd_jack *jack;124	int rval;125 126	rval = snd_soc_card_jack_new(card, "HDMI Jack",	SND_JACK_LINEOUT,127				     &pdata->hdmi_jack);128 129	if (rval < 0) {130		dev_err(card->dev, "Unable to add HDMI Jack\n");131		return rval;132	}133 134	jack = pdata->hdmi_jack.jack;135	jack->private_data = component;136	jack->private_free = sc7280_jack_free;137 138	return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);139}140 141static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd)142{143	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);144	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);145	struct snd_soc_card *card = rtd->card;146	struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);147	int ret;148 149	if (++data->pri_mi2s_clk_count == 1) {150		snd_soc_dai_set_sysclk(cpu_dai,151			LPASS_MCLK0,152			DEFAULT_MCLK_RATE,153			SNDRV_PCM_STREAM_PLAYBACK);154	}155	snd_soc_dai_set_fmt(codec_dai,156				SND_SOC_DAIFMT_CBC_CFC |157				SND_SOC_DAIFMT_NB_NF |158				SND_SOC_DAIFMT_I2S);159 160	ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,161					DEFAULT_MCLK_RATE, RT5682_PLL_FREQ);162	if (ret) {163		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);164		return ret;165	}166 167	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,168					RT5682_PLL_FREQ,169					SND_SOC_CLOCK_IN);170 171	if (ret) {172		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",173			ret);174		return ret;175	}176 177	return 0;178}179 180static int sc7280_init(struct snd_soc_pcm_runtime *rtd)181{182	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);183 184	switch (cpu_dai->id) {185	case MI2S_PRIMARY:186	case LPASS_CDC_DMA_TX3:187	case TX_CODEC_DMA_TX_3:188		return sc7280_headset_init(rtd);189	case LPASS_CDC_DMA_RX0:190	case LPASS_CDC_DMA_VA_TX0:191	case MI2S_SECONDARY:192	case RX_CODEC_DMA_RX_0:193	case SECONDARY_MI2S_RX:194	case VA_CODEC_DMA_TX_0:195		return 0;196	case LPASS_DP_RX:197		return sc7280_hdmi_init(rtd);198	default:199		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);200	}201 202	return -EINVAL;203}204 205static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,206				struct snd_pcm_hw_params *params)207{208	struct snd_pcm_runtime *runtime = substream->runtime;209	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);210	struct snd_soc_dai *codec_dai;211	const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);212	struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);213	struct sdw_stream_runtime *sruntime;214	int i;215 216	if (!rtd->dai_link->no_pcm) {217		snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);218		snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000);219	}220 221	switch (cpu_dai->id) {222	case LPASS_CDC_DMA_TX3:223	case LPASS_CDC_DMA_RX0:224	case RX_CODEC_DMA_RX_0:225	case SECONDARY_MI2S_RX:226	case TX_CODEC_DMA_TX_3:227	case VA_CODEC_DMA_TX_0:228		for_each_rtd_codec_dais(rtd, i, codec_dai) {229			sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);230			if (sruntime != ERR_PTR(-ENOTSUPP))231				pdata->sruntime[cpu_dai->id] = sruntime;232		}233		break;234	}235 236	return 0;237}238 239static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream)240{241	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);242	const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);243	struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);244	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];245	int ret;246 247	if (!sruntime)248		return 0;249 250	if (data->stream_prepared[cpu_dai->id]) {251		sdw_disable_stream(sruntime);252		sdw_deprepare_stream(sruntime);253		data->stream_prepared[cpu_dai->id] = false;254	}255 256	ret = sdw_prepare_stream(sruntime);257	if (ret)258		return ret;259 260	ret = sdw_enable_stream(sruntime);261	if (ret) {262		sdw_deprepare_stream(sruntime);263		return ret;264	}265	data->stream_prepared[cpu_dai->id] = true;266 267	return ret;268}269 270static int sc7280_snd_prepare(struct snd_pcm_substream *substream)271{272	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);273	const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);274 275	switch (cpu_dai->id) {276	case LPASS_CDC_DMA_RX0:277	case LPASS_CDC_DMA_TX3:278	case RX_CODEC_DMA_RX_0:279	case TX_CODEC_DMA_TX_3:280	case VA_CODEC_DMA_TX_0:281		return sc7280_snd_swr_prepare(substream);282	default:283		break;284	}285 286	return 0;287}288 289static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)290{291	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);292	struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);293	const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);294	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];295 296	switch (cpu_dai->id) {297	case LPASS_CDC_DMA_RX0:298	case LPASS_CDC_DMA_TX3:299	case RX_CODEC_DMA_RX_0:300	case TX_CODEC_DMA_TX_3:301	case VA_CODEC_DMA_TX_0:302		if (sruntime && data->stream_prepared[cpu_dai->id]) {303			sdw_disable_stream(sruntime);304			sdw_deprepare_stream(sruntime);305			data->stream_prepared[cpu_dai->id] = false;306		}307		break;308	default:309		break;310	}311	return 0;312}313 314static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)315{316	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);317	struct snd_soc_card *card = rtd->card;318	struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);319	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);320	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];321 322	switch (cpu_dai->id) {323	case MI2S_PRIMARY:324		if (--data->pri_mi2s_clk_count == 0) {325			snd_soc_dai_set_sysclk(cpu_dai,326					       LPASS_MCLK0,327					       0,328					       SNDRV_PCM_STREAM_PLAYBACK);329		}330		break;331	case SECONDARY_MI2S_RX:332		snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,333					       0, SNDRV_PCM_STREAM_PLAYBACK);334		break;335	default:336		break;337	}338 339	data->sruntime[cpu_dai->id] = NULL;340	sdw_release_stream(sruntime);341}342 343static int sc7280_snd_startup(struct snd_pcm_substream *substream)344{345	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;346	unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;347	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);348	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);349	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);350	int ret = 0;351 352	switch (cpu_dai->id) {353	case MI2S_PRIMARY:354		ret = sc7280_rt5682_init(rtd);355		if (ret)356			return ret;357		break;358	case SECONDARY_MI2S_RX:359		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;360 361		snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,362			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);363 364		snd_soc_dai_set_fmt(cpu_dai, fmt);365		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);366		break;367	default:368		break;369	}370 371	return qcom_snd_sdw_startup(substream);372}373 374static const struct snd_soc_ops sc7280_ops = {375	.startup = sc7280_snd_startup,376	.hw_params = sc7280_snd_hw_params,377	.hw_free = sc7280_snd_hw_free,378	.prepare = sc7280_snd_prepare,379	.shutdown = sc7280_snd_shutdown,380};381 382static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {383	SND_SOC_DAPM_HP("Headphone Jack", NULL),384	SND_SOC_DAPM_MIC("Headset Mic", NULL),385};386 387static const struct snd_kcontrol_new sc7280_snd_controls[] = {388	SOC_DAPM_PIN_SWITCH("Headphone Jack"),389	SOC_DAPM_PIN_SWITCH("Headset Mic"),390};391 392static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,393					 struct snd_pcm_hw_params *params)394{395	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);396	struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);397	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);398 399	rate->min = rate->max = 48000;400	channels->min = channels->max = 2;401	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);402 403	return 0;404}405 406static int sc7280_snd_platform_probe(struct platform_device *pdev)407{408	struct snd_soc_card *card;409	struct sc7280_snd_data *data;410	struct device *dev = &pdev->dev;411	struct snd_soc_dai_link *link;412	int ret, i;413 414	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);415	if (!data)416		return -ENOMEM;417 418	card = &data->card;419	snd_soc_card_set_drvdata(card, data);420 421	card->owner = THIS_MODULE;422	card->driver_name = "SC7280";423	card->dev = dev;424 425	card->dapm_widgets = sc7280_snd_widgets;426	card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);427	card->controls = sc7280_snd_controls;428	card->num_controls = ARRAY_SIZE(sc7280_snd_controls);429 430	ret = qcom_snd_parse_of(card);431	if (ret)432		return ret;433 434	for_each_card_prelinks(card, i, link) {435		link->init = sc7280_init;436		link->ops = &sc7280_ops;437		if (link->no_pcm == 1)438			link->be_hw_params_fixup = sc7280_snd_be_hw_params_fixup;439	}440 441	return devm_snd_soc_register_card(dev, card);442}443 444static const struct of_device_id sc7280_snd_device_id[]  = {445	{ .compatible = "google,sc7280-herobrine" },446	{}447};448MODULE_DEVICE_TABLE(of, sc7280_snd_device_id);449 450static struct platform_driver sc7280_snd_driver = {451	.probe = sc7280_snd_platform_probe,452	.driver = {453		.name = "msm-snd-sc7280",454		.of_match_table = sc7280_snd_device_id,455		.pm = &snd_soc_pm_ops,456	},457};458module_platform_driver(sc7280_snd_driver);459 460MODULE_DESCRIPTION("sc7280 ASoC Machine Driver");461MODULE_LICENSE("GPL");462