brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · 296caad Raw
295 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// uda1334.c  --  UDA1334 ALSA SoC Audio driver4//5// Based on WM8523 ALSA SoC Audio driver written by Mark Brown6 7#include <linux/mod_devicetable.h>8#include <linux/module.h>9#include <linux/moduleparam.h>10#include <linux/init.h>11#include <linux/delay.h>12#include <linux/slab.h>13#include <linux/gpio/consumer.h>14#include <sound/core.h>15#include <sound/pcm.h>16#include <sound/pcm_params.h>17#include <sound/soc.h>18#include <sound/initval.h>19 20#define UDA1334_NUM_RATES 621 22/* codec private data */23struct uda1334_priv {24	struct gpio_desc *mute;25	struct gpio_desc *deemph;26	unsigned int sysclk;27	unsigned int rate_constraint_list[UDA1334_NUM_RATES];28	struct snd_pcm_hw_constraint_list rate_constraint;29};30 31static const struct snd_soc_dapm_widget uda1334_dapm_widgets[] = {32SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),33SND_SOC_DAPM_OUTPUT("LINEVOUTL"),34SND_SOC_DAPM_OUTPUT("LINEVOUTR"),35};36 37static const struct snd_soc_dapm_route uda1334_dapm_routes[] = {38	{ "LINEVOUTL", NULL, "DAC" },39	{ "LINEVOUTR", NULL, "DAC" },40};41 42static int uda1334_put_deemph(struct snd_kcontrol *kcontrol,43			      struct snd_ctl_elem_value *ucontrol)44{45	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);46	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);47	int deemph = ucontrol->value.integer.value[0];48 49	if (deemph > 1)50		return -EINVAL;51 52	gpiod_set_value_cansleep(uda1334->deemph, deemph);53 54	return 0;55};56 57static int uda1334_get_deemph(struct snd_kcontrol *kcontrol,58			      struct snd_ctl_elem_value *ucontrol)59{60	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);61	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);62	int ret;63 64	ret = gpiod_get_value_cansleep(uda1334->deemph);65	if (ret < 0)66		return -EINVAL;67 68	ucontrol->value.integer.value[0] = ret;69 70	return 0;71};72 73static const struct snd_kcontrol_new uda1334_snd_controls[] = {74	SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,75			    uda1334_get_deemph, uda1334_put_deemph),76};77 78static const struct {79	int value;80	int ratio;81} lrclk_ratios[UDA1334_NUM_RATES] = {82	{ 1, 128 },83	{ 2, 192 },84	{ 3, 256 },85	{ 4, 384 },86	{ 5, 512 },87	{ 6, 768 },88};89 90static int uda1334_startup(struct snd_pcm_substream *substream,91			   struct snd_soc_dai *dai)92{93	struct snd_soc_component *component = dai->component;94	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);95 96	/*97	 * The set of sample rates that can be supported depends on the98	 * MCLK supplied to the CODEC - enforce this.99	 */100	if (!uda1334->sysclk) {101		dev_err(component->dev,102			"No MCLK configured, call set_sysclk() on init\n");103		return -EINVAL;104	}105 106	snd_pcm_hw_constraint_list(substream->runtime, 0,107				   SNDRV_PCM_HW_PARAM_RATE,108				   &uda1334->rate_constraint);109 110	gpiod_set_value_cansleep(uda1334->mute, 1);111 112	return 0;113}114 115static void uda1334_shutdown(struct snd_pcm_substream *substream,116			     struct snd_soc_dai *dai)117{118	struct snd_soc_component *component = dai->component;119	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);120 121	gpiod_set_value_cansleep(uda1334->mute, 0);122}123 124static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai,125				  int clk_id, unsigned int freq, int dir)126{127	struct snd_soc_component *component = codec_dai->component;128	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);129	unsigned int val;130	int i, j = 0;131 132	uda1334->sysclk = freq;133 134	uda1334->rate_constraint.count = 0;135	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {136		val = freq / lrclk_ratios[i].ratio;137		/*138		 * Check that it's a standard rate since core can't139		 * cope with others and having the odd rates confuses140		 * constraint matching.141		 */142 143		switch (val) {144		case 8000:145		case 32000:146		case 44100:147		case 48000:148		case 64000:149		case 88200:150		case 96000:151			dev_dbg(component->dev, "Supported sample rate: %dHz\n",152				val);153			uda1334->rate_constraint_list[j++] = val;154			uda1334->rate_constraint.count++;155			break;156		default:157			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",158				val);159		}160	}161 162	/* Need at least one supported rate... */163	if (uda1334->rate_constraint.count == 0)164		return -EINVAL;165 166	return 0;167}168 169static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)170{171	fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |172		SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);173 174	if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |175		    SND_SOC_DAIFMT_CBC_CFC)) {176		dev_err(codec_dai->dev, "Invalid DAI format\n");177		return -EINVAL;178	}179 180	return 0;181}182 183static int uda1334_mute_stream(struct snd_soc_dai *dai, int mute, int stream)184{185	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(dai->component);186 187	if (uda1334->mute)188		gpiod_set_value_cansleep(uda1334->mute, mute);189 190	return 0;191}192 193#define UDA1334_RATES SNDRV_PCM_RATE_8000_96000194 195#define UDA1334_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)196 197static const struct snd_soc_dai_ops uda1334_dai_ops = {198	.startup	= uda1334_startup,199	.shutdown	= uda1334_shutdown,200	.set_sysclk	= uda1334_set_dai_sysclk,201	.set_fmt	= uda1334_set_fmt,202	.mute_stream	= uda1334_mute_stream,203};204 205static struct snd_soc_dai_driver uda1334_dai = {206	.name = "uda1334-hifi",207	.playback = {208		.stream_name = "Playback",209		.channels_min = 2,210		.channels_max = 2,211		.rates = UDA1334_RATES,212		.formats = UDA1334_FORMATS,213	},214	.ops = &uda1334_dai_ops,215};216 217static int uda1334_probe(struct snd_soc_component *component)218{219	struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);220 221	uda1334->rate_constraint.list = &uda1334->rate_constraint_list[0];222	uda1334->rate_constraint.count =223		ARRAY_SIZE(uda1334->rate_constraint_list);224 225	return 0;226}227 228static const struct snd_soc_component_driver soc_component_dev_uda1334 = {229	.probe			= uda1334_probe,230	.controls		= uda1334_snd_controls,231	.num_controls		= ARRAY_SIZE(uda1334_snd_controls),232	.dapm_widgets		= uda1334_dapm_widgets,233	.num_dapm_widgets	= ARRAY_SIZE(uda1334_dapm_widgets),234	.dapm_routes		= uda1334_dapm_routes,235	.num_dapm_routes	= ARRAY_SIZE(uda1334_dapm_routes),236	.idle_bias_on		= 1,237	.use_pmdown_time	= 1,238	.endianness		= 1,239};240 241static const struct of_device_id uda1334_of_match[] = {242	{ .compatible = "nxp,uda1334" },243	{ /* sentinel*/ }244};245MODULE_DEVICE_TABLE(of, uda1334_of_match);246 247static int uda1334_codec_probe(struct platform_device *pdev)248{249	struct uda1334_priv *uda1334;250	int ret;251 252	uda1334 = devm_kzalloc(&pdev->dev, sizeof(struct uda1334_priv),253			       GFP_KERNEL);254	if (!uda1334)255		return -ENOMEM;256 257	platform_set_drvdata(pdev, uda1334);258 259	uda1334->mute = devm_gpiod_get(&pdev->dev, "nxp,mute", GPIOD_OUT_LOW);260	if (IS_ERR(uda1334->mute)) {261		ret = PTR_ERR(uda1334->mute);262		dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret);263		return ret;264	}265 266	uda1334->deemph = devm_gpiod_get(&pdev->dev, "nxp,deemph", GPIOD_OUT_LOW);267	if (IS_ERR(uda1334->deemph)) {268		ret = PTR_ERR(uda1334->deemph);269		dev_err(&pdev->dev, "Failed to get deemph line: %d\n", ret);270		return ret;271	}272 273	ret = devm_snd_soc_register_component(&pdev->dev,274					      &soc_component_dev_uda1334,275					      &uda1334_dai, 1);276	if (ret < 0)277		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);278 279	return ret;280}281 282static struct platform_driver uda1334_codec_driver = {283	.probe		= uda1334_codec_probe,284	.driver		= {285		.name	= "uda1334-codec",286		.of_match_table = uda1334_of_match,287	},288};289module_platform_driver(uda1334_codec_driver);290 291MODULE_DESCRIPTION("ASoC UDA1334 driver");292MODULE_AUTHOR("Andra Danciu <andradanciu1997@gmail.com>");293MODULE_ALIAS("platform:uda1334-codec");294MODULE_LICENSE("GPL v2");295