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

rockchip_max98090.c (12170B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Rockchip machine ASoC driver for boards using a MAX90809 CODEC.
      4 *
      5 * Copyright (c) 2014, ROCKCHIP CORPORATION.  All rights reserved.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/of_device.h>
     10#include <linux/platform_device.h>
     11#include <linux/slab.h>
     12#include <linux/gpio.h>
     13#include <linux/of_gpio.h>
     14#include <sound/core.h>
     15#include <sound/jack.h>
     16#include <sound/pcm.h>
     17#include <sound/pcm_params.h>
     18#include <sound/soc.h>
     19
     20#include "rockchip_i2s.h"
     21#include "../codecs/ts3a227e.h"
     22
     23#define DRV_NAME "rockchip-snd-max98090"
     24
     25static struct snd_soc_jack headset_jack;
     26
     27/* Headset jack detection DAPM pins */
     28static struct snd_soc_jack_pin headset_jack_pins[] = {
     29	{
     30		.pin = "Headphone",
     31		.mask = SND_JACK_HEADPHONE,
     32	},
     33	{
     34		.pin = "Headset Mic",
     35		.mask = SND_JACK_MICROPHONE,
     36	},
     37
     38};
     39
     40#define RK_MAX98090_WIDGETS \
     41	SND_SOC_DAPM_HP("Headphone", NULL), \
     42	SND_SOC_DAPM_MIC("Headset Mic", NULL), \
     43	SND_SOC_DAPM_MIC("Int Mic", NULL), \
     44	SND_SOC_DAPM_SPK("Speaker", NULL)
     45
     46#define RK_HDMI_WIDGETS \
     47	SND_SOC_DAPM_LINE("HDMI", NULL)
     48
     49static const struct snd_soc_dapm_widget rk_max98090_dapm_widgets[] = {
     50	RK_MAX98090_WIDGETS,
     51};
     52
     53static const struct snd_soc_dapm_widget rk_hdmi_dapm_widgets[] = {
     54	RK_HDMI_WIDGETS,
     55};
     56
     57static const struct snd_soc_dapm_widget rk_max98090_hdmi_dapm_widgets[] = {
     58	RK_MAX98090_WIDGETS,
     59	RK_HDMI_WIDGETS,
     60};
     61
     62#define RK_MAX98090_AUDIO_MAP \
     63	{"IN34", NULL, "Headset Mic"}, \
     64	{"Headset Mic", NULL, "MICBIAS"}, \
     65	{"DMICL", NULL, "Int Mic"}, \
     66	{"Headphone", NULL, "HPL"}, \
     67	{"Headphone", NULL, "HPR"}, \
     68	{"Speaker", NULL, "SPKL"}, \
     69	{"Speaker", NULL, "SPKR"}
     70
     71#define RK_HDMI_AUDIO_MAP \
     72	{"HDMI", NULL, "TX"}
     73
     74static const struct snd_soc_dapm_route rk_max98090_audio_map[] = {
     75	RK_MAX98090_AUDIO_MAP,
     76};
     77
     78static const struct snd_soc_dapm_route rk_hdmi_audio_map[] = {
     79	RK_HDMI_AUDIO_MAP,
     80};
     81
     82static const struct snd_soc_dapm_route rk_max98090_hdmi_audio_map[] = {
     83	RK_MAX98090_AUDIO_MAP,
     84	RK_HDMI_AUDIO_MAP,
     85};
     86
     87#define RK_MAX98090_CONTROLS \
     88	SOC_DAPM_PIN_SWITCH("Headphone"), \
     89	SOC_DAPM_PIN_SWITCH("Headset Mic"), \
     90	SOC_DAPM_PIN_SWITCH("Int Mic"), \
     91	SOC_DAPM_PIN_SWITCH("Speaker")
     92
     93#define RK_HDMI_CONTROLS \
     94	SOC_DAPM_PIN_SWITCH("HDMI")
     95
     96static const struct snd_kcontrol_new rk_max98090_controls[] = {
     97	RK_MAX98090_CONTROLS,
     98};
     99
    100static const struct snd_kcontrol_new rk_hdmi_controls[] = {
    101	RK_HDMI_CONTROLS,
    102};
    103
    104static const struct snd_kcontrol_new rk_max98090_hdmi_controls[] = {
    105	RK_MAX98090_CONTROLS,
    106	RK_HDMI_CONTROLS,
    107};
    108
    109static int rk_jack_event(struct notifier_block *nb, unsigned long event,
    110			 void *data)
    111{
    112	struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
    113	struct snd_soc_dapm_context *dapm = &jack->card->dapm;
    114
    115	if (event & SND_JACK_MICROPHONE) {
    116		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
    117		snd_soc_dapm_force_enable_pin(dapm, "SHDN");
    118	} else {
    119		snd_soc_dapm_disable_pin(dapm, "MICBIAS");
    120		snd_soc_dapm_disable_pin(dapm, "SHDN");
    121	}
    122
    123	snd_soc_dapm_sync(dapm);
    124
    125	return 0;
    126}
    127
    128static struct notifier_block rk_jack_nb = {
    129	.notifier_call = rk_jack_event,
    130};
    131
    132static int rk_init(struct snd_soc_pcm_runtime *runtime)
    133{
    134	/*
    135	 * The jack has already been created in the rk_98090_headset_init()
    136	 * function.
    137	 */
    138	snd_soc_jack_notifier_register(&headset_jack, &rk_jack_nb);
    139
    140	return 0;
    141}
    142
    143static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
    144			     struct snd_pcm_hw_params *params)
    145{
    146	int ret = 0;
    147	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    148	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    149	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    150	int mclk;
    151
    152	switch (params_rate(params)) {
    153	case 8000:
    154	case 16000:
    155	case 24000:
    156	case 32000:
    157	case 48000:
    158	case 64000:
    159	case 96000:
    160		mclk = 12288000;
    161		break;
    162	case 11025:
    163	case 22050:
    164	case 44100:
    165	case 88200:
    166		mclk = 11289600;
    167		break;
    168	default:
    169		return -EINVAL;
    170	}
    171
    172	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
    173				     SND_SOC_CLOCK_OUT);
    174	if (ret) {
    175		dev_err(cpu_dai->dev, "Can't set cpu dai clock %d\n", ret);
    176		return ret;
    177	}
    178
    179	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
    180				     SND_SOC_CLOCK_IN);
    181
    182	/* HDMI codec dai does not need to set sysclk. */
    183	if (!strcmp(rtd->dai_link->name, "HDMI"))
    184		return 0;
    185
    186	if (ret) {
    187		dev_err(codec_dai->dev, "Can't set codec dai clock %d\n", ret);
    188		return ret;
    189	}
    190
    191	return ret;
    192}
    193
    194static int rk_aif1_startup(struct snd_pcm_substream *substream)
    195{
    196	/*
    197	 * Set period size to 240 because pl330 has issue
    198	 * dealing with larger period in stress testing.
    199	 */
    200	return snd_pcm_hw_constraint_minmax(substream->runtime,
    201			SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 240, 240);
    202}
    203
    204static const struct snd_soc_ops rk_aif1_ops = {
    205	.hw_params = rk_aif1_hw_params,
    206	.startup = rk_aif1_startup,
    207};
    208
    209SND_SOC_DAILINK_DEFS(analog,
    210		     DAILINK_COMP_ARRAY(COMP_EMPTY()),
    211		     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
    212		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
    213
    214SND_SOC_DAILINK_DEFS(hdmi,
    215		     DAILINK_COMP_ARRAY(COMP_EMPTY()),
    216		     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
    217		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
    218
    219enum {
    220	DAILINK_MAX98090,
    221	DAILINK_HDMI,
    222};
    223
    224static struct snd_soc_jack rk_hdmi_jack;
    225
    226static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime)
    227{
    228	struct snd_soc_card *card = runtime->card;
    229	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
    230	int ret;
    231
    232	/* enable jack detection */
    233	ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
    234				    &rk_hdmi_jack);
    235	if (ret) {
    236		dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
    237		return ret;
    238	}
    239
    240	return snd_soc_component_set_jack(component, &rk_hdmi_jack, NULL);
    241}
    242
    243/* max98090 dai_link */
    244static struct snd_soc_dai_link rk_max98090_dailinks[] = {
    245	{
    246		.name = "max98090",
    247		.stream_name = "Analog",
    248		.init = rk_init,
    249		.ops = &rk_aif1_ops,
    250		/* set max98090 as slave */
    251		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    252			SND_SOC_DAIFMT_CBS_CFS,
    253		SND_SOC_DAILINK_REG(analog),
    254	},
    255};
    256
    257/* HDMI codec dai_link */
    258static struct snd_soc_dai_link rk_hdmi_dailinks[] = {
    259	{
    260		.name = "HDMI",
    261		.stream_name = "HDMI",
    262		.init = rk_hdmi_init,
    263		.ops = &rk_aif1_ops,
    264		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    265			SND_SOC_DAIFMT_CBS_CFS,
    266		SND_SOC_DAILINK_REG(hdmi),
    267	}
    268};
    269
    270/* max98090 and HDMI codec dai_link */
    271static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = {
    272	[DAILINK_MAX98090] = {
    273		.name = "max98090",
    274		.stream_name = "Analog",
    275		.init = rk_init,
    276		.ops = &rk_aif1_ops,
    277		/* set max98090 as slave */
    278		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    279			SND_SOC_DAIFMT_CBS_CFS,
    280		SND_SOC_DAILINK_REG(analog),
    281	},
    282	[DAILINK_HDMI] = {
    283		.name = "HDMI",
    284		.stream_name = "HDMI",
    285		.init = rk_hdmi_init,
    286		.ops = &rk_aif1_ops,
    287		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    288			SND_SOC_DAIFMT_CBS_CFS,
    289		SND_SOC_DAILINK_REG(hdmi),
    290	}
    291};
    292
    293static int rk_98090_headset_init(struct snd_soc_component *component);
    294
    295static struct snd_soc_aux_dev rk_98090_headset_dev = {
    296	.dlc = COMP_EMPTY(),
    297	.init = rk_98090_headset_init,
    298};
    299
    300static struct snd_soc_card rockchip_max98090_card = {
    301	.name = "ROCKCHIP-I2S",
    302	.owner = THIS_MODULE,
    303	.dai_link = rk_max98090_dailinks,
    304	.num_links = ARRAY_SIZE(rk_max98090_dailinks),
    305	.aux_dev = &rk_98090_headset_dev,
    306	.num_aux_devs = 1,
    307	.dapm_widgets = rk_max98090_dapm_widgets,
    308	.num_dapm_widgets = ARRAY_SIZE(rk_max98090_dapm_widgets),
    309	.dapm_routes = rk_max98090_audio_map,
    310	.num_dapm_routes = ARRAY_SIZE(rk_max98090_audio_map),
    311	.controls = rk_max98090_controls,
    312	.num_controls = ARRAY_SIZE(rk_max98090_controls),
    313};
    314
    315static struct snd_soc_card rockchip_hdmi_card = {
    316	.name = "ROCKCHIP-HDMI",
    317	.owner = THIS_MODULE,
    318	.dai_link = rk_hdmi_dailinks,
    319	.num_links = ARRAY_SIZE(rk_hdmi_dailinks),
    320	.dapm_widgets = rk_hdmi_dapm_widgets,
    321	.num_dapm_widgets = ARRAY_SIZE(rk_hdmi_dapm_widgets),
    322	.dapm_routes = rk_hdmi_audio_map,
    323	.num_dapm_routes = ARRAY_SIZE(rk_hdmi_audio_map),
    324	.controls = rk_hdmi_controls,
    325	.num_controls = ARRAY_SIZE(rk_hdmi_controls),
    326};
    327
    328static struct snd_soc_card rockchip_max98090_hdmi_card = {
    329	.name = "ROCKCHIP-MAX98090-HDMI",
    330	.owner = THIS_MODULE,
    331	.dai_link = rk_max98090_hdmi_dailinks,
    332	.num_links = ARRAY_SIZE(rk_max98090_hdmi_dailinks),
    333	.aux_dev = &rk_98090_headset_dev,
    334	.num_aux_devs = 1,
    335	.dapm_widgets = rk_max98090_hdmi_dapm_widgets,
    336	.num_dapm_widgets = ARRAY_SIZE(rk_max98090_hdmi_dapm_widgets),
    337	.dapm_routes = rk_max98090_hdmi_audio_map,
    338	.num_dapm_routes = ARRAY_SIZE(rk_max98090_hdmi_audio_map),
    339	.controls = rk_max98090_hdmi_controls,
    340	.num_controls = ARRAY_SIZE(rk_max98090_hdmi_controls),
    341};
    342
    343static int rk_98090_headset_init(struct snd_soc_component *component)
    344{
    345	int ret;
    346
    347	/* Enable Headset and 4 Buttons Jack detection */
    348	ret = snd_soc_card_jack_new_pins(component->card, "Headset Jack",
    349					 SND_JACK_HEADSET |
    350					 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
    351					 SND_JACK_BTN_2 | SND_JACK_BTN_3,
    352					 &headset_jack,
    353					 headset_jack_pins,
    354					 ARRAY_SIZE(headset_jack_pins));
    355	if (ret)
    356		return ret;
    357
    358	ret = ts3a227e_enable_jack_detect(component, &headset_jack);
    359
    360	return ret;
    361}
    362
    363static int rk_parse_headset_from_of(struct device *dev, struct device_node *np)
    364{
    365	rk_98090_headset_dev.dlc.of_node = of_parse_phandle(
    366			np, "rockchip,headset-codec", 0);
    367	if (!rk_98090_headset_dev.dlc.of_node) {
    368		dev_err(dev,
    369			"Property 'rockchip,headset-codec' missing/invalid\n");
    370		return -EINVAL;
    371	}
    372	return 0;
    373}
    374
    375static int snd_rk_mc_probe(struct platform_device *pdev)
    376{
    377	int ret = 0;
    378	struct snd_soc_card *card;
    379	struct device *dev = &pdev->dev;
    380	struct device_node *np = pdev->dev.of_node;
    381	struct device_node *np_cpu;
    382	struct device_node *np_audio, *np_hdmi;
    383
    384	/* Parse DTS for I2S controller. */
    385	np_cpu = of_parse_phandle(np, "rockchip,i2s-controller", 0);
    386
    387	if (!np_cpu) {
    388		dev_err(&pdev->dev,
    389			"Property 'rockchip,i2s-controller missing or invalid\n");
    390		return -EINVAL;
    391	}
    392
    393	/*
    394	 * Find the card to use based on the presences of audio codec
    395	 * and hdmi codec in device property. Set their of_node accordingly.
    396	 */
    397	np_audio = of_parse_phandle(np, "rockchip,audio-codec", 0);
    398	np_hdmi = of_parse_phandle(np, "rockchip,hdmi-codec", 0);
    399	if (np_audio && np_hdmi) {
    400		card = &rockchip_max98090_hdmi_card;
    401		card->dai_link[DAILINK_MAX98090].codecs->of_node = np_audio;
    402		card->dai_link[DAILINK_HDMI].codecs->of_node = np_hdmi;
    403		card->dai_link[DAILINK_MAX98090].cpus->of_node = np_cpu;
    404		card->dai_link[DAILINK_MAX98090].platforms->of_node = np_cpu;
    405		card->dai_link[DAILINK_HDMI].cpus->of_node = np_cpu;
    406		card->dai_link[DAILINK_HDMI].platforms->of_node = np_cpu;
    407	} else if (np_audio) {
    408		card = &rockchip_max98090_card;
    409		card->dai_link[0].codecs->of_node = np_audio;
    410		card->dai_link[0].cpus->of_node = np_cpu;
    411		card->dai_link[0].platforms->of_node = np_cpu;
    412	} else if (np_hdmi) {
    413		card = &rockchip_hdmi_card;
    414		card->dai_link[0].codecs->of_node = np_hdmi;
    415		card->dai_link[0].cpus->of_node = np_cpu;
    416		card->dai_link[0].platforms->of_node = np_cpu;
    417	} else {
    418		dev_err(dev, "At least one of codecs should be specified\n");
    419		return -EINVAL;
    420	}
    421
    422	card->dev = dev;
    423
    424	/* Parse headset detection codec. */
    425	if (np_audio) {
    426		ret = rk_parse_headset_from_of(dev, np);
    427		if (ret)
    428			return ret;
    429	}
    430
    431	/* Parse card name. */
    432	ret = snd_soc_of_parse_card_name(card, "rockchip,model");
    433	if (ret) {
    434		dev_err(&pdev->dev,
    435			"Soc parse card name failed %d\n", ret);
    436		return ret;
    437	}
    438
    439	/* register the soc card */
    440	ret = devm_snd_soc_register_card(&pdev->dev, card);
    441	if (ret) {
    442		dev_err(&pdev->dev,
    443			"Soc register card failed %d\n", ret);
    444		return ret;
    445	}
    446
    447	return ret;
    448}
    449
    450static const struct of_device_id rockchip_max98090_of_match[] = {
    451	{ .compatible = "rockchip,rockchip-audio-max98090", },
    452	{},
    453};
    454
    455MODULE_DEVICE_TABLE(of, rockchip_max98090_of_match);
    456
    457static struct platform_driver snd_rk_mc_driver = {
    458	.probe = snd_rk_mc_probe,
    459	.driver = {
    460		.name = DRV_NAME,
    461		.pm = &snd_soc_pm_ops,
    462		.of_match_table = rockchip_max98090_of_match,
    463	},
    464};
    465
    466module_platform_driver(snd_rk_mc_driver);
    467
    468MODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>");
    469MODULE_DESCRIPTION("Rockchip max98090 machine ASoC driver");
    470MODULE_LICENSE("GPL v2");
    471MODULE_ALIAS("platform:" DRV_NAME);