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

cht_bsw_nau8824.c (8643B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  cht-bsw-nau8824.c - ASoc Machine driver for Intel Cherryview-based
      4 *          platforms Cherrytrail and Braswell, with nau8824 codec.
      5 *
      6 *  Copyright (C) 2018 Intel Corp
      7 *  Copyright (C) 2018 Nuvoton Technology Corp
      8 *
      9 *  Author: Wang, Joseph C <joequant@gmail.com>
     10 *  Co-author: John Hsu <KCHSU0@nuvoton.com>
     11 *  This file is based on cht_bsw_rt5672.c and cht-bsw-max98090.c
     12 */
     13
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16#include <linux/slab.h>
     17#include <sound/pcm.h>
     18#include <sound/pcm_params.h>
     19#include <sound/soc.h>
     20#include <sound/soc-acpi.h>
     21#include <sound/jack.h>
     22#include <linux/input.h>
     23#include "../atom/sst-atom-controls.h"
     24#include "../../codecs/nau8824.h"
     25
     26struct cht_mc_private {
     27	struct snd_soc_jack jack;
     28};
     29
     30static struct snd_soc_jack_pin cht_bsw_jack_pins[] = {
     31	{
     32		.pin = "Headphone",
     33		.mask = SND_JACK_HEADPHONE,
     34	},
     35	{
     36		.pin = "Headset Mic",
     37		.mask = SND_JACK_MICROPHONE,
     38	},
     39};
     40
     41static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
     42	SND_SOC_DAPM_HP("Headphone", NULL),
     43	SND_SOC_DAPM_MIC("Headset Mic", NULL),
     44	SND_SOC_DAPM_MIC("Int Mic", NULL),
     45	SND_SOC_DAPM_SPK("Ext Spk", NULL),
     46};
     47
     48static const struct snd_soc_dapm_route cht_audio_map[] = {
     49	{"Ext Spk", NULL, "SPKOUTL"},
     50	{"Ext Spk", NULL, "SPKOUTR"},
     51	{"Headphone", NULL, "HPOL"},
     52	{"Headphone", NULL, "HPOR"},
     53	{"MIC1", NULL, "Int Mic"},
     54	{"MIC2", NULL, "Int Mic"},
     55	{"HSMIC1", NULL, "Headset Mic"},
     56	{"HSMIC2", NULL, "Headset Mic"},
     57	{"Playback", NULL, "ssp2 Tx"},
     58	{"ssp2 Tx", NULL, "codec_out0"},
     59	{"ssp2 Tx", NULL, "codec_out1"},
     60	{"codec_in0", NULL, "ssp2 Rx" },
     61	{"codec_in1", NULL, "ssp2 Rx" },
     62	{"ssp2 Rx", NULL, "Capture"},
     63};
     64
     65static const struct snd_kcontrol_new cht_mc_controls[] = {
     66	SOC_DAPM_PIN_SWITCH("Headphone"),
     67	SOC_DAPM_PIN_SWITCH("Headset Mic"),
     68	SOC_DAPM_PIN_SWITCH("Int Mic"),
     69	SOC_DAPM_PIN_SWITCH("Ext Spk"),
     70};
     71
     72static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
     73	struct snd_pcm_hw_params *params)
     74{
     75	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     76	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
     77	int ret;
     78
     79	ret = snd_soc_dai_set_sysclk(codec_dai, NAU8824_CLK_FLL_FS, 0,
     80		SND_SOC_CLOCK_IN);
     81	if (ret < 0) {
     82		dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
     83		return ret;
     84	}
     85	ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params),
     86		params_rate(params) * 256);
     87	if (ret < 0) {
     88		dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
     89		return ret;
     90	}
     91
     92	return 0;
     93}
     94
     95static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
     96{
     97	struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
     98	struct snd_soc_jack *jack = &ctx->jack;
     99	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
    100	struct snd_soc_component *component = codec_dai->component;
    101	int ret, jack_type;
    102
    103	/* NAU88L24 supports 4 buttons headset detection
    104	 * KEY_PLAYPAUSE
    105	 * KEY_VOICECOMMAND
    106	 * KEY_VOLUMEUP
    107	 * KEY_VOLUMEDOWN
    108	 */
    109	jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
    110		SND_JACK_BTN_2 | SND_JACK_BTN_3;
    111	ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type,
    112		jack, cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
    113	if (ret) {
    114		dev_err(runtime->dev,
    115			"Headset Jack creation failed %d\n", ret);
    116		return ret;
    117	}
    118	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
    119	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
    120	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
    121	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
    122
    123	nau8824_enable_jack_detect(component, jack);
    124
    125	return ret;
    126}
    127
    128static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
    129	struct snd_pcm_hw_params *params)
    130{
    131	struct snd_interval *rate = hw_param_interval(params,
    132		SNDRV_PCM_HW_PARAM_RATE);
    133	struct snd_interval *channels = hw_param_interval(params,
    134		SNDRV_PCM_HW_PARAM_CHANNELS);
    135	struct snd_mask *fmt =
    136		hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
    137	int ret;
    138
    139	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
    140	rate->min = rate->max = 48000;
    141	channels->min = channels->max = 2;
    142
    143	/* set SSP2 to 24-bit */
    144	snd_mask_none(fmt);
    145	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
    146
    147	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
    148	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
    149	if (ret < 0) {
    150		dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
    151		return ret;
    152	}
    153
    154	return 0;
    155}
    156
    157static int cht_aif1_startup(struct snd_pcm_substream *substream)
    158{
    159	return snd_pcm_hw_constraint_single(substream->runtime,
    160		SNDRV_PCM_HW_PARAM_RATE, 48000);
    161}
    162
    163static const struct snd_soc_ops cht_aif1_ops = {
    164	.startup = cht_aif1_startup,
    165};
    166
    167static const struct snd_soc_ops cht_be_ssp2_ops = {
    168	.hw_params = cht_aif1_hw_params,
    169};
    170
    171SND_SOC_DAILINK_DEF(dummy,
    172	DAILINK_COMP_ARRAY(COMP_DUMMY()));
    173
    174SND_SOC_DAILINK_DEF(media,
    175	DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
    176
    177SND_SOC_DAILINK_DEF(deepbuffer,
    178	DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
    179
    180SND_SOC_DAILINK_DEF(ssp2_port,
    181	DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
    182SND_SOC_DAILINK_DEF(ssp2_codec,
    183	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508824:00",
    184				      NAU8824_CODEC_DAI)));
    185
    186SND_SOC_DAILINK_DEF(platform,
    187	DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
    188
    189static struct snd_soc_dai_link cht_dailink[] = {
    190	/* Front End DAI links */
    191	[MERR_DPCM_AUDIO] = {
    192		.name = "Audio Port",
    193		.stream_name = "Audio",
    194		.nonatomic = true,
    195		.dynamic = 1,
    196		.dpcm_playback = 1,
    197		.dpcm_capture = 1,
    198		.ops = &cht_aif1_ops,
    199		SND_SOC_DAILINK_REG(media, dummy, platform),
    200	},
    201	[MERR_DPCM_DEEP_BUFFER] = {
    202		.name = "Deep-Buffer Audio Port",
    203		.stream_name = "Deep-Buffer Audio",
    204		.nonatomic = true,
    205		.dynamic = 1,
    206		.dpcm_playback = 1,
    207		.ops = &cht_aif1_ops,
    208		SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
    209	},
    210	/* Back End DAI links */
    211	{
    212		/* SSP2 - Codec */
    213		.name = "SSP2-Codec",
    214		.id = 0,
    215		.no_pcm = 1,
    216		.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
    217			| SND_SOC_DAIFMT_CBC_CFC,
    218		.init = cht_codec_init,
    219		.be_hw_params_fixup = cht_codec_fixup,
    220		.dpcm_playback = 1,
    221		.dpcm_capture = 1,
    222		.ops = &cht_be_ssp2_ops,
    223		SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
    224	},
    225};
    226
    227/* use space before codec name to simplify card ID, and simplify driver name */
    228#define SOF_CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */
    229#define SOF_DRIVER_NAME "SOF"
    230
    231#define CARD_NAME "chtnau8824"
    232#define DRIVER_NAME NULL /* card name will be used for driver name */
    233
    234/* SoC card */
    235static struct snd_soc_card snd_soc_card_cht = {
    236	.owner = THIS_MODULE,
    237	.dai_link = cht_dailink,
    238	.num_links = ARRAY_SIZE(cht_dailink),
    239	.dapm_widgets = cht_dapm_widgets,
    240	.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
    241	.dapm_routes = cht_audio_map,
    242	.num_dapm_routes = ARRAY_SIZE(cht_audio_map),
    243	.controls = cht_mc_controls,
    244	.num_controls = ARRAY_SIZE(cht_mc_controls),
    245};
    246
    247static int snd_cht_mc_probe(struct platform_device *pdev)
    248{
    249	struct cht_mc_private *drv;
    250	struct snd_soc_acpi_mach *mach;
    251	const char *platform_name;
    252	bool sof_parent;
    253	int ret_val;
    254
    255	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
    256	if (!drv)
    257		return -ENOMEM;
    258	snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
    259
    260	/* override platform name, if required */
    261	snd_soc_card_cht.dev = &pdev->dev;
    262	mach = pdev->dev.platform_data;
    263	platform_name = mach->mach_params.platform;
    264
    265	ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
    266							platform_name);
    267	if (ret_val)
    268		return ret_val;
    269
    270	sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
    271
    272	/* set card and driver name */
    273	if (sof_parent) {
    274		snd_soc_card_cht.name = SOF_CARD_NAME;
    275		snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
    276	} else {
    277		snd_soc_card_cht.name = CARD_NAME;
    278		snd_soc_card_cht.driver_name = DRIVER_NAME;
    279	}
    280
    281	snd_soc_card_cht.components = nau8824_components();
    282
    283	/* set pm ops */
    284	if (sof_parent)
    285		pdev->dev.driver->pm = &snd_soc_pm_ops;
    286
    287	/* register the soc card */
    288	ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
    289	if (ret_val) {
    290		dev_err(&pdev->dev,
    291			"snd_soc_register_card failed %d\n", ret_val);
    292		return ret_val;
    293	}
    294	platform_set_drvdata(pdev, &snd_soc_card_cht);
    295
    296	return ret_val;
    297}
    298
    299static struct platform_driver snd_cht_mc_driver = {
    300	.driver = {
    301		.name = "cht-bsw-nau8824",
    302	},
    303	.probe = snd_cht_mc_probe,
    304};
    305
    306module_platform_driver(snd_cht_mc_driver);
    307
    308MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
    309MODULE_AUTHOR("Wang, Joseph C <joequant@gmail.com>");
    310MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
    311MODULE_LICENSE("GPL v2");
    312MODULE_ALIAS("platform:cht-bsw-nau8824");