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

uda1334.c (7656B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2//
      3// uda1334.c  --  UDA1334 ALSA SoC Audio driver
      4//
      5// Based on WM8523 ALSA SoC Audio driver written by Mark Brown
      6
      7#include <linux/module.h>
      8#include <linux/moduleparam.h>
      9#include <linux/init.h>
     10#include <linux/delay.h>
     11#include <linux/slab.h>
     12#include <linux/gpio/consumer.h>
     13#include <linux/of_device.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 6
     21
     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 the
     98	 * 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't
    139		 * cope with others and having the odd rates confuses
    140		 * 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_MASTER_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_96000
    194
    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	.non_legacy_dai_naming	= 1,
    240};
    241
    242static const struct of_device_id uda1334_of_match[] = {
    243	{ .compatible = "nxp,uda1334" },
    244	{ /* sentinel*/ }
    245};
    246MODULE_DEVICE_TABLE(of, uda1334_of_match);
    247
    248static int uda1334_codec_probe(struct platform_device *pdev)
    249{
    250	struct uda1334_priv *uda1334;
    251	int ret;
    252
    253	uda1334 = devm_kzalloc(&pdev->dev, sizeof(struct uda1334_priv),
    254			       GFP_KERNEL);
    255	if (!uda1334)
    256		return -ENOMEM;
    257
    258	platform_set_drvdata(pdev, uda1334);
    259
    260	uda1334->mute = devm_gpiod_get(&pdev->dev, "nxp,mute", GPIOD_OUT_LOW);
    261	if (IS_ERR(uda1334->mute)) {
    262		ret = PTR_ERR(uda1334->mute);
    263		dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret);
    264		return ret;
    265	}
    266
    267	uda1334->deemph = devm_gpiod_get(&pdev->dev, "nxp,deemph", GPIOD_OUT_LOW);
    268	if (IS_ERR(uda1334->deemph)) {
    269		ret = PTR_ERR(uda1334->deemph);
    270		dev_err(&pdev->dev, "Failed to get deemph line: %d\n", ret);
    271		return ret;
    272	}
    273
    274	ret = devm_snd_soc_register_component(&pdev->dev,
    275					      &soc_component_dev_uda1334,
    276					      &uda1334_dai, 1);
    277	if (ret < 0)
    278		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
    279
    280	return ret;
    281}
    282
    283static struct platform_driver uda1334_codec_driver = {
    284	.probe		= uda1334_codec_probe,
    285	.driver		= {
    286		.name	= "uda1334-codec",
    287		.of_match_table = uda1334_of_match,
    288	},
    289};
    290module_platform_driver(uda1334_codec_driver);
    291
    292MODULE_DESCRIPTION("ASoC UDA1334 driver");
    293MODULE_AUTHOR("Andra Danciu <andradanciu1997@gmail.com>");
    294MODULE_ALIAS("platform:uda1334-codec");
    295MODULE_LICENSE("GPL v2");