brintos

brintos / linux-shallow public Read only

0
0
Text · 15.8 KiB · 6c89c73 Raw
628 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA72194 *5 * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.6 */7 8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/slab.h>11#include <linux/delay.h>12#include <linux/spi/spi.h>13#include <linux/i2c.h>14#include <linux/input.h>15#include <sound/core.h>16#include <sound/jack.h>17#include <sound/pcm.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20#include "rockchip_i2s.h"21#include "../codecs/da7219.h"22#include "../codecs/rt5514.h"23 24#define DRV_NAME "rk3399-gru-sound"25 26#define SOUND_FS	25627 28static unsigned int dmic_wakeup_delay;29 30static struct snd_soc_jack rockchip_sound_jack;31 32/* Headset jack detection DAPM pins */33static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {34	{35		.pin = "Headphones",36		.mask = SND_JACK_HEADPHONE,37	},38	{39		.pin = "Headset Mic",40		.mask = SND_JACK_MICROPHONE,41	},42	{43		.pin = "Line Out",44		.mask = SND_JACK_LINEOUT,45	},46};47 48static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {49	SND_SOC_DAPM_HP("Headphones", NULL),50	SND_SOC_DAPM_SPK("Speakers", NULL),51	SND_SOC_DAPM_MIC("Headset Mic", NULL),52	SND_SOC_DAPM_LINE("Line Out", NULL),53	SND_SOC_DAPM_MIC("Int Mic", NULL),54	SND_SOC_DAPM_LINE("HDMI", NULL),55};56 57static const struct snd_kcontrol_new rockchip_controls[] = {58	SOC_DAPM_PIN_SWITCH("Headphones"),59	SOC_DAPM_PIN_SWITCH("Speakers"),60	SOC_DAPM_PIN_SWITCH("Headset Mic"),61	SOC_DAPM_PIN_SWITCH("Line Out"),62	SOC_DAPM_PIN_SWITCH("Int Mic"),63	SOC_DAPM_PIN_SWITCH("HDMI"),64};65 66static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,67			     struct snd_pcm_hw_params *params)68{69	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);70	unsigned int mclk;71	int ret;72 73	mclk = params_rate(params) * SOUND_FS;74 75	ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);76	if (ret) {77		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",78				__func__, mclk, ret);79		return ret;80	}81 82	return 0;83}84 85static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,86			     struct snd_pcm_hw_params *params)87{88	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);89	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);90	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);91	unsigned int mclk;92	int ret;93 94	mclk = params_rate(params) * SOUND_FS;95 96	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,97				     SND_SOC_CLOCK_OUT);98	if (ret < 0) {99		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);100		return ret;101	}102 103	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,104				     mclk, SND_SOC_CLOCK_IN);105	if (ret) {106		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",107				__func__, params_rate(params) * 512, ret);108		return ret;109	}110 111	/* Wait for DMIC stable */112	msleep(dmic_wakeup_delay);113 114	return 0;115}116 117static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,118			     struct snd_pcm_hw_params *params)119{120	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);121	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);122	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);123	int mclk, ret;124 125	/* in bypass mode, the mclk has to be one of the frequencies below */126	switch (params_rate(params)) {127	case 8000:128	case 16000:129	case 24000:130	case 32000:131	case 48000:132	case 64000:133	case 96000:134		mclk = 12288000;135		break;136	case 11025:137	case 22050:138	case 44100:139	case 88200:140		mclk = 11289600;141		break;142	default:143		return -EINVAL;144	}145 146	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,147				     SND_SOC_CLOCK_OUT);148	if (ret < 0) {149		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);150		return ret;151	}152 153	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,154				     SND_SOC_CLOCK_IN);155	if (ret < 0) {156		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);157		return ret;158	}159 160	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);161	if (ret < 0) {162		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);163		return ret;164	}165 166	return 0;167}168 169static struct snd_soc_jack cdn_dp_card_jack;170 171static int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)172{173	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;174	struct snd_soc_card *card = rtd->card;175	int ret;176 177	/* Enable jack detection. */178	ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT,179				    &cdn_dp_card_jack);180	if (ret) {181		dev_err(card->dev, "Can't create DP Jack %d\n", ret);182		return ret;183	}184 185	return snd_soc_component_set_jack(component, &cdn_dp_card_jack, NULL);186}187 188static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)189{190	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;191	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);192	int ret;193 194	/* We need default MCLK and PLL settings for the accessory detection */195	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,196				     SND_SOC_CLOCK_IN);197	if (ret < 0) {198		dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);199		return ret;200	}201 202	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);203	if (ret < 0) {204		dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);205		return ret;206	}207 208	/* Enable Headset and 4 Buttons Jack detection */209	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",210					 SND_JACK_HEADSET | SND_JACK_LINEOUT |211					 SND_JACK_BTN_0 | SND_JACK_BTN_1 |212					 SND_JACK_BTN_2 | SND_JACK_BTN_3,213					 &rockchip_sound_jack,214					 rockchip_sound_jack_pins,215					 ARRAY_SIZE(rockchip_sound_jack_pins));216 217	if (ret) {218		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);219		return ret;220	}221 222	snd_jack_set_key(223		rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);224	snd_jack_set_key(225		rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);226	snd_jack_set_key(227		rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);228	snd_jack_set_key(229		rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);230 231	snd_soc_component_set_jack(component, &rockchip_sound_jack, NULL);232 233	return 0;234}235 236static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,237			     struct snd_pcm_hw_params *params)238{239	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);240	unsigned int mclk;241	int ret;242 243	mclk = params_rate(params) * SOUND_FS;244 245	ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);246	if (ret) {247		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",248				__func__, mclk, ret);249		return ret;250	}251 252	/* Wait for DMIC stable */253	msleep(dmic_wakeup_delay);254 255	return 0;256}257 258static int rockchip_sound_startup(struct snd_pcm_substream *substream)259{260	struct snd_pcm_runtime *runtime = substream->runtime;261 262	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;263	return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,264			8000, 96000);265}266 267static const struct snd_soc_ops rockchip_sound_max98357a_ops = {268	.startup = rockchip_sound_startup,269	.hw_params = rockchip_sound_max98357a_hw_params,270};271 272static const struct snd_soc_ops rockchip_sound_rt5514_ops = {273	.startup = rockchip_sound_startup,274	.hw_params = rockchip_sound_rt5514_hw_params,275};276 277static const struct snd_soc_ops rockchip_sound_da7219_ops = {278	.startup = rockchip_sound_startup,279	.hw_params = rockchip_sound_da7219_hw_params,280};281 282static const struct snd_soc_ops rockchip_sound_dmic_ops = {283	.startup = rockchip_sound_startup,284	.hw_params = rockchip_sound_dmic_hw_params,285};286 287static struct snd_soc_card rockchip_sound_card = {288	.name = "rk3399-gru-sound",289	.owner = THIS_MODULE,290	.dapm_widgets = rockchip_dapm_widgets,291	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),292	.controls = rockchip_controls,293	.num_controls = ARRAY_SIZE(rockchip_controls),294};295 296enum {297	DAILINK_CDNDP,298	DAILINK_DA7219,299	DAILINK_DMIC,300	DAILINK_MAX98357A,301	DAILINK_RT5514,302	DAILINK_RT5514_DSP,303};304 305SND_SOC_DAILINK_DEFS(cdndp,306	DAILINK_COMP_ARRAY(COMP_EMPTY()),307	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")),308	DAILINK_COMP_ARRAY(COMP_EMPTY()));309 310SND_SOC_DAILINK_DEFS(da7219,311	DAILINK_COMP_ARRAY(COMP_EMPTY()),312	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")),313	DAILINK_COMP_ARRAY(COMP_EMPTY()));314 315SND_SOC_DAILINK_DEFS(dmic,316	DAILINK_COMP_ARRAY(COMP_EMPTY()),317	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")),318	DAILINK_COMP_ARRAY(COMP_EMPTY()));319 320SND_SOC_DAILINK_DEFS(max98357a,321	DAILINK_COMP_ARRAY(COMP_EMPTY()),322	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),323	DAILINK_COMP_ARRAY(COMP_EMPTY()));324 325SND_SOC_DAILINK_DEFS(rt5514,326	DAILINK_COMP_ARRAY(COMP_EMPTY()),327	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")),328	DAILINK_COMP_ARRAY(COMP_EMPTY()));329 330SND_SOC_DAILINK_DEFS(rt5514_dsp,331	DAILINK_COMP_ARRAY(COMP_EMPTY()),332	DAILINK_COMP_ARRAY(COMP_DUMMY()),333	DAILINK_COMP_ARRAY(COMP_EMPTY()));334 335static const struct snd_soc_dai_link rockchip_dais[] = {336	[DAILINK_CDNDP] = {337		.name = "DP",338		.stream_name = "DP PCM",339		.init = rockchip_sound_cdndp_init,340		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |341			SND_SOC_DAIFMT_CBS_CFS,342		SND_SOC_DAILINK_REG(cdndp),343	},344	[DAILINK_DA7219] = {345		.name = "DA7219",346		.stream_name = "DA7219 PCM",347		.init = rockchip_sound_da7219_init,348		.ops = &rockchip_sound_da7219_ops,349		/* set da7219 as slave */350		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |351			SND_SOC_DAIFMT_CBS_CFS,352		SND_SOC_DAILINK_REG(da7219),353	},354	[DAILINK_DMIC] = {355		.name = "DMIC",356		.stream_name = "DMIC PCM",357		.ops = &rockchip_sound_dmic_ops,358		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |359			SND_SOC_DAIFMT_CBS_CFS,360		SND_SOC_DAILINK_REG(dmic),361	},362	[DAILINK_MAX98357A] = {363		.name = "MAX98357A",364		.stream_name = "MAX98357A PCM",365		.ops = &rockchip_sound_max98357a_ops,366		/* set max98357a as slave */367		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |368			SND_SOC_DAIFMT_CBS_CFS,369		SND_SOC_DAILINK_REG(max98357a),370	},371	[DAILINK_RT5514] = {372		.name = "RT5514",373		.stream_name = "RT5514 PCM",374		.ops = &rockchip_sound_rt5514_ops,375		/* set rt5514 as slave */376		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |377			SND_SOC_DAIFMT_CBS_CFS,378		SND_SOC_DAILINK_REG(rt5514),379	},380	/* RT5514 DSP for voice wakeup via spi bus */381	[DAILINK_RT5514_DSP] = {382		.name = "RT5514 DSP",383		.stream_name = "Wake on Voice",384		SND_SOC_DAILINK_REG(rt5514_dsp),385	},386};387 388static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {389	/* Output */390	{"HDMI", NULL, "TX"},391};392 393static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {394	/* Output */395	{"Headphones", NULL, "HPL"},396	{"Headphones", NULL, "HPR"},397 398	/* Input */399	{"MIC", NULL, "Headset Mic"},400};401 402static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {403	/* Input */404	{"DMic", NULL, "Int Mic"},405};406 407static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {408	/* Output */409	{"Speakers", NULL, "Speaker"},410};411 412static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {413	/* Input */414	{"DMIC1L", NULL, "Int Mic"},415	{"DMIC1R", NULL, "Int Mic"},416};417 418struct rockchip_sound_route {419	const struct snd_soc_dapm_route *routes;420	int num_routes;421};422 423static const struct rockchip_sound_route rockchip_routes[] = {424	[DAILINK_CDNDP] = {425		.routes = rockchip_sound_cdndp_routes,426		.num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),427	},428	[DAILINK_DA7219] = {429		.routes = rockchip_sound_da7219_routes,430		.num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),431	},432	[DAILINK_DMIC] = {433		.routes = rockchip_sound_dmic_routes,434		.num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),435	},436	[DAILINK_MAX98357A] = {437		.routes = rockchip_sound_max98357a_routes,438		.num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),439	},440	[DAILINK_RT5514] = {441		.routes = rockchip_sound_rt5514_routes,442		.num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),443	},444	[DAILINK_RT5514_DSP] = {},445};446 447struct dailink_match_data {448	const char *compatible;449	const struct bus_type *bus_type;450};451 452static const struct dailink_match_data dailink_match[] = {453	[DAILINK_CDNDP] = {454		.compatible = "rockchip,rk3399-cdn-dp",455	},456	[DAILINK_DA7219] = {457		.compatible = "dlg,da7219",458	},459	[DAILINK_DMIC] = {460		.compatible = "dmic-codec",461	},462	[DAILINK_MAX98357A] = {463		.compatible = "maxim,max98357a",464	},465	[DAILINK_RT5514] = {466		.compatible = "realtek,rt5514",467		.bus_type = &i2c_bus_type,468	},469	[DAILINK_RT5514_DSP] = {470		.compatible = "realtek,rt5514",471		.bus_type = &spi_bus_type,472	},473};474 475static int rockchip_sound_codec_node_match(struct device_node *np_codec)476{477	struct device *dev;478	int i;479 480	for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {481		if (!of_device_is_compatible(np_codec,482					     dailink_match[i].compatible))483			continue;484 485		if (dailink_match[i].bus_type) {486			dev = bus_find_device_by_of_node(dailink_match[i].bus_type,487							 np_codec);488			if (!dev)489				continue;490			put_device(dev);491		}492 493		return i;494	}495	return -1;496}497 498static int rockchip_sound_of_parse_dais(struct device *dev,499					struct snd_soc_card *card)500{501	struct device_node *np_cpu, *np_cpu0, *np_cpu1;502	struct device_node *np_codec;503	struct snd_soc_dai_link *dai;504	struct snd_soc_dapm_route *routes;505	int i, index;506	int num_routes;507 508	card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),509				      GFP_KERNEL);510	if (!card->dai_link)511		return -ENOMEM;512 513	num_routes = 0;514	for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)515		num_routes += rockchip_routes[i].num_routes;516	routes = devm_kcalloc(dev, num_routes, sizeof(*routes),517			      GFP_KERNEL);518	if (!routes)519		return -ENOMEM;520	card->dapm_routes = routes;521 522	np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);523	np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);524 525	card->num_dapm_routes = 0;526	card->num_links = 0;527	for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {528		np_codec = of_parse_phandle(dev->of_node,529					    "rockchip,codec", i);530		if (!np_codec)531			break;532 533		if (!of_device_is_available(np_codec))534			continue;535 536		index = rockchip_sound_codec_node_match(np_codec);537		if (index < 0)538			continue;539 540		switch (index) {541		case DAILINK_CDNDP:542			np_cpu = np_cpu1;543			break;544		case DAILINK_RT5514_DSP:545			np_cpu = np_codec;546			break;547		default:548			np_cpu = np_cpu0;549			break;550		}551 552		if (!np_cpu) {553			dev_err(dev, "Missing 'rockchip,cpu' for %s\n",554				rockchip_dais[index].name);555			return -EINVAL;556		}557 558		dai = &card->dai_link[card->num_links++];559		*dai = rockchip_dais[index];560 561		if (!dai->codecs->name)562			dai->codecs->of_node = np_codec;563		dai->platforms->of_node = np_cpu;564		dai->cpus->of_node = np_cpu;565 566		if (card->num_dapm_routes + rockchip_routes[index].num_routes >567		    num_routes) {568			dev_err(dev, "Too many routes\n");569			return -EINVAL;570		}571 572		memcpy(routes + card->num_dapm_routes,573		       rockchip_routes[index].routes,574		       rockchip_routes[index].num_routes * sizeof(*routes));575		card->num_dapm_routes += rockchip_routes[index].num_routes;576	}577 578	return 0;579}580 581static int rockchip_sound_probe(struct platform_device *pdev)582{583	struct snd_soc_card *card = &rockchip_sound_card;584	int ret;585 586	ret = rockchip_sound_of_parse_dais(&pdev->dev, card);587	if (ret < 0) {588		dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);589		return ret;590	}591 592	/* Set DMIC wakeup delay */593	ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",594					&dmic_wakeup_delay);595	if (ret) {596		dmic_wakeup_delay = 0;597		dev_dbg(&pdev->dev,598			"no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");599	}600 601	card->dev = &pdev->dev;602	return devm_snd_soc_register_card(&pdev->dev, card);603}604 605static const struct of_device_id rockchip_sound_of_match[] = {606	{ .compatible = "rockchip,rk3399-gru-sound", },607	{},608};609 610static struct platform_driver rockchip_sound_driver = {611	.probe = rockchip_sound_probe,612	.driver = {613		.name = DRV_NAME,614		.of_match_table = rockchip_sound_of_match,615#ifdef CONFIG_PM616		.pm = &snd_soc_pm_ops,617#endif618	},619};620 621module_platform_driver(rockchip_sound_driver);622 623MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");624MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");625MODULE_LICENSE("GPL v2");626MODULE_ALIAS("platform:" DRV_NAME);627MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);628