cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sc7280.c (9783B)


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