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

sm8250.c (8005B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (c) 2020, Linaro Limited
      3
      4#include <linux/module.h>
      5#include <linux/platform_device.h>
      6#include <linux/of_device.h>
      7#include <sound/soc.h>
      8#include <sound/soc-dapm.h>
      9#include <sound/pcm.h>
     10#include <linux/soundwire/sdw.h>
     11#include <sound/jack.h>
     12#include <linux/input-event-codes.h>
     13#include "qdsp6/q6afe.h"
     14#include "common.h"
     15
     16#define DRIVER_NAME		"sm8250"
     17#define MI2S_BCLK_RATE		1536000
     18
     19struct sm8250_snd_data {
     20	bool stream_prepared[AFE_PORT_MAX];
     21	struct snd_soc_card *card;
     22	struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
     23	struct snd_soc_jack jack;
     24	bool jack_setup;
     25};
     26
     27static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
     28{
     29	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
     30	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     31	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     32	struct snd_soc_card *card = rtd->card;
     33	int rval, i;
     34
     35	if (!data->jack_setup) {
     36		struct snd_jack *jack;
     37
     38		rval = snd_soc_card_jack_new(card, "Headset Jack",
     39					     SND_JACK_HEADSET | SND_JACK_LINEOUT |
     40					     SND_JACK_MECHANICAL |
     41					     SND_JACK_BTN_0 | SND_JACK_BTN_1 |
     42					     SND_JACK_BTN_2 | SND_JACK_BTN_3 |
     43					     SND_JACK_BTN_4 | SND_JACK_BTN_5,
     44					     &data->jack);
     45
     46		if (rval < 0) {
     47			dev_err(card->dev, "Unable to add Headphone Jack\n");
     48			return rval;
     49		}
     50
     51		jack = data->jack.jack;
     52
     53		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA);
     54		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
     55		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
     56		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
     57		data->jack_setup = true;
     58	}
     59
     60	switch (cpu_dai->id) {
     61	case TX_CODEC_DMA_TX_0:
     62	case TX_CODEC_DMA_TX_1:
     63	case TX_CODEC_DMA_TX_2:
     64	case TX_CODEC_DMA_TX_3:
     65		for_each_rtd_codec_dais(rtd, i, codec_dai) {
     66			rval = snd_soc_component_set_jack(codec_dai->component,
     67							  &data->jack, NULL);
     68			if (rval != 0 && rval != -ENOTSUPP) {
     69				dev_warn(card->dev, "Failed to set jack: %d\n", rval);
     70				return rval;
     71			}
     72		}
     73
     74		break;
     75	default:
     76		break;
     77	}
     78
     79
     80	return 0;
     81}
     82
     83static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
     84				     struct snd_pcm_hw_params *params)
     85{
     86	struct snd_interval *rate = hw_param_interval(params,
     87					SNDRV_PCM_HW_PARAM_RATE);
     88	struct snd_interval *channels = hw_param_interval(params,
     89					SNDRV_PCM_HW_PARAM_CHANNELS);
     90
     91	rate->min = rate->max = 48000;
     92	channels->min = channels->max = 2;
     93
     94	return 0;
     95}
     96
     97static int sm8250_snd_startup(struct snd_pcm_substream *substream)
     98{
     99	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
    100	unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
    101	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    102	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    103	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    104
    105	switch (cpu_dai->id) {
    106	case TERTIARY_MI2S_RX:
    107		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
    108		snd_soc_dai_set_sysclk(cpu_dai,
    109			Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
    110			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
    111		snd_soc_dai_set_fmt(cpu_dai, fmt);
    112		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
    113		break;
    114	default:
    115		break;
    116	}
    117	return 0;
    118}
    119
    120static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
    121				struct snd_pcm_hw_params *params)
    122{
    123	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    124	struct snd_soc_dai *codec_dai;
    125	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    126	struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
    127	struct sdw_stream_runtime *sruntime;
    128	int i;
    129
    130	switch (cpu_dai->id) {
    131	case WSA_CODEC_DMA_RX_0:
    132	case RX_CODEC_DMA_RX_0:
    133	case RX_CODEC_DMA_RX_1:
    134	case TX_CODEC_DMA_TX_0:
    135	case TX_CODEC_DMA_TX_1:
    136	case TX_CODEC_DMA_TX_2:
    137	case TX_CODEC_DMA_TX_3:
    138		for_each_rtd_codec_dais(rtd, i, codec_dai) {
    139			sruntime = snd_soc_dai_get_stream(codec_dai,
    140							  substream->stream);
    141			if (sruntime != ERR_PTR(-ENOTSUPP))
    142				pdata->sruntime[cpu_dai->id] = sruntime;
    143		}
    144		break;
    145	}
    146
    147	return 0;
    148
    149}
    150
    151static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream)
    152{
    153	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    154	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    155	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
    156	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
    157	int ret;
    158
    159	if (!sruntime)
    160		return 0;
    161
    162	if (data->stream_prepared[cpu_dai->id]) {
    163		sdw_disable_stream(sruntime);
    164		sdw_deprepare_stream(sruntime);
    165		data->stream_prepared[cpu_dai->id] = false;
    166	}
    167
    168	ret = sdw_prepare_stream(sruntime);
    169	if (ret)
    170		return ret;
    171
    172	/**
    173	 * NOTE: there is a strict hw requirement about the ordering of port
    174	 * enables and actual WSA881x PA enable. PA enable should only happen
    175	 * after soundwire ports are enabled if not DC on the line is
    176	 * accumulated resulting in Click/Pop Noise
    177	 * PA enable/mute are handled as part of codec DAPM and digital mute.
    178	 */
    179
    180	ret = sdw_enable_stream(sruntime);
    181	if (ret) {
    182		sdw_deprepare_stream(sruntime);
    183		return ret;
    184	}
    185	data->stream_prepared[cpu_dai->id]  = true;
    186
    187	return ret;
    188}
    189
    190static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
    191{
    192	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    193	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    194
    195	switch (cpu_dai->id) {
    196	case WSA_CODEC_DMA_RX_0:
    197	case WSA_CODEC_DMA_RX_1:
    198	case RX_CODEC_DMA_RX_0:
    199	case RX_CODEC_DMA_RX_1:
    200	case TX_CODEC_DMA_TX_0:
    201	case TX_CODEC_DMA_TX_1:
    202	case TX_CODEC_DMA_TX_2:
    203	case TX_CODEC_DMA_TX_3:
    204		return sm8250_snd_wsa_dma_prepare(substream);
    205	default:
    206		break;
    207	}
    208
    209	return 0;
    210}
    211
    212static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
    213{
    214	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    215	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
    216	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    217	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
    218
    219	switch (cpu_dai->id) {
    220	case WSA_CODEC_DMA_RX_0:
    221	case WSA_CODEC_DMA_RX_1:
    222	case RX_CODEC_DMA_RX_0:
    223	case RX_CODEC_DMA_RX_1:
    224	case TX_CODEC_DMA_TX_0:
    225	case TX_CODEC_DMA_TX_1:
    226	case TX_CODEC_DMA_TX_2:
    227	case TX_CODEC_DMA_TX_3:
    228		if (sruntime && data->stream_prepared[cpu_dai->id]) {
    229			sdw_disable_stream(sruntime);
    230			sdw_deprepare_stream(sruntime);
    231			data->stream_prepared[cpu_dai->id] = false;
    232		}
    233		break;
    234	default:
    235		break;
    236	}
    237
    238	return 0;
    239}
    240
    241static const struct snd_soc_ops sm8250_be_ops = {
    242	.startup = sm8250_snd_startup,
    243	.hw_params = sm8250_snd_hw_params,
    244	.hw_free = sm8250_snd_hw_free,
    245	.prepare = sm8250_snd_prepare,
    246};
    247
    248static void sm8250_add_be_ops(struct snd_soc_card *card)
    249{
    250	struct snd_soc_dai_link *link;
    251	int i;
    252
    253	for_each_card_prelinks(card, i, link) {
    254		if (link->no_pcm == 1) {
    255			link->init = sm8250_snd_init;
    256			link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
    257			link->ops = &sm8250_be_ops;
    258		}
    259	}
    260}
    261
    262static int sm8250_platform_probe(struct platform_device *pdev)
    263{
    264	struct snd_soc_card *card;
    265	struct sm8250_snd_data *data;
    266	struct device *dev = &pdev->dev;
    267	int ret;
    268
    269	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
    270	if (!card)
    271		return -ENOMEM;
    272
    273	/* Allocate the private data */
    274	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    275	if (!data)
    276		return -ENOMEM;
    277
    278	card->dev = dev;
    279	dev_set_drvdata(dev, card);
    280	snd_soc_card_set_drvdata(card, data);
    281	ret = qcom_snd_parse_of(card);
    282	if (ret)
    283		return ret;
    284
    285	card->driver_name = DRIVER_NAME;
    286	sm8250_add_be_ops(card);
    287	return devm_snd_soc_register_card(dev, card);
    288}
    289
    290static const struct of_device_id snd_sm8250_dt_match[] = {
    291	{.compatible = "qcom,sm8250-sndcard"},
    292	{.compatible = "qcom,qrb5165-rb5-sndcard"},
    293	{}
    294};
    295
    296MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match);
    297
    298static struct platform_driver snd_sm8250_driver = {
    299	.probe  = sm8250_platform_probe,
    300	.driver = {
    301		.name = "snd-sm8250",
    302		.of_match_table = snd_sm8250_dt_match,
    303	},
    304};
    305module_platform_driver(snd_sm8250_driver);
    306MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
    307MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
    308MODULE_LICENSE("GPL v2");