brintos

brintos / linux-shallow public Read only

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