xref: /openbmc/linux/sound/soc/codecs/cq93vc.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b56e972bSMiguel Aguilar /*
3b56e972bSMiguel Aguilar  * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
4b56e972bSMiguel Aguilar  *
5b56e972bSMiguel Aguilar  * Copyright (C) 2010 Texas Instruments, Inc
6b56e972bSMiguel Aguilar  *
7b56e972bSMiguel Aguilar  * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
8b56e972bSMiguel Aguilar  */
9b56e972bSMiguel Aguilar #include <linux/module.h>
10b56e972bSMiguel Aguilar #include <linux/moduleparam.h>
11b56e972bSMiguel Aguilar #include <linux/init.h>
12b56e972bSMiguel Aguilar #include <linux/io.h>
13b56e972bSMiguel Aguilar #include <linux/delay.h>
14b56e972bSMiguel Aguilar #include <linux/pm.h>
15b56e972bSMiguel Aguilar #include <linux/platform_device.h>
16b56e972bSMiguel Aguilar #include <linux/device.h>
17923a0042STejun Heo #include <linux/slab.h>
18b56e972bSMiguel Aguilar #include <linux/clk.h>
19b56e972bSMiguel Aguilar #include <linux/mfd/davinci_voicecodec.h>
20f0fba2adSLiam Girdwood #include <linux/spi/spi.h>
21b56e972bSMiguel Aguilar 
22b56e972bSMiguel Aguilar #include <sound/core.h>
23b56e972bSMiguel Aguilar #include <sound/pcm.h>
24b56e972bSMiguel Aguilar #include <sound/pcm_params.h>
25b56e972bSMiguel Aguilar #include <sound/soc.h>
26b56e972bSMiguel Aguilar #include <sound/initval.h>
27b56e972bSMiguel Aguilar 
28b56e972bSMiguel Aguilar static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
29b56e972bSMiguel Aguilar 	SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
30b56e972bSMiguel Aguilar 	SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
31b56e972bSMiguel Aguilar };
32b56e972bSMiguel Aguilar 
cq93vc_mute(struct snd_soc_dai * dai,int mute,int direction)33*54b59270SKuninori Morimoto static int cq93vc_mute(struct snd_soc_dai *dai, int mute, int direction)
34b56e972bSMiguel Aguilar {
354f404f38SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
361201939aSMark Brown 	u8 reg;
37b56e972bSMiguel Aguilar 
38b56e972bSMiguel Aguilar 	if (mute)
391201939aSMark Brown 		reg = DAVINCI_VC_REG09_MUTE;
40b56e972bSMiguel Aguilar 	else
411201939aSMark Brown 		reg = 0;
421201939aSMark Brown 
434f404f38SKuninori Morimoto 	snd_soc_component_update_bits(component, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
441201939aSMark Brown 			    reg);
45b56e972bSMiguel Aguilar 
46b56e972bSMiguel Aguilar 	return 0;
47b56e972bSMiguel Aguilar }
48b56e972bSMiguel Aguilar 
cq93vc_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)49b56e972bSMiguel Aguilar static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
50b56e972bSMiguel Aguilar 				 int clk_id, unsigned int freq, int dir)
51b56e972bSMiguel Aguilar {
52b56e972bSMiguel Aguilar 	switch (freq) {
53b56e972bSMiguel Aguilar 	case 22579200:
54b56e972bSMiguel Aguilar 	case 27000000:
55b56e972bSMiguel Aguilar 	case 33868800:
56b56e972bSMiguel Aguilar 		return 0;
57b56e972bSMiguel Aguilar 	}
58b56e972bSMiguel Aguilar 
59b56e972bSMiguel Aguilar 	return -EINVAL;
60b56e972bSMiguel Aguilar }
61b56e972bSMiguel Aguilar 
cq93vc_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)624f404f38SKuninori Morimoto static int cq93vc_set_bias_level(struct snd_soc_component *component,
63b56e972bSMiguel Aguilar 				enum snd_soc_bias_level level)
64b56e972bSMiguel Aguilar {
65b56e972bSMiguel Aguilar 	switch (level) {
66b56e972bSMiguel Aguilar 	case SND_SOC_BIAS_ON:
674f404f38SKuninori Morimoto 		snd_soc_component_write(component, DAVINCI_VC_REG12,
68b56e972bSMiguel Aguilar 			     DAVINCI_VC_REG12_POWER_ALL_ON);
69b56e972bSMiguel Aguilar 		break;
70b56e972bSMiguel Aguilar 	case SND_SOC_BIAS_PREPARE:
71b56e972bSMiguel Aguilar 		break;
72b56e972bSMiguel Aguilar 	case SND_SOC_BIAS_STANDBY:
734f404f38SKuninori Morimoto 		snd_soc_component_write(component, DAVINCI_VC_REG12,
74b56e972bSMiguel Aguilar 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
75b56e972bSMiguel Aguilar 		break;
76b56e972bSMiguel Aguilar 	case SND_SOC_BIAS_OFF:
77b56e972bSMiguel Aguilar 		/* force all power off */
784f404f38SKuninori Morimoto 		snd_soc_component_write(component, DAVINCI_VC_REG12,
79b56e972bSMiguel Aguilar 			     DAVINCI_VC_REG12_POWER_ALL_OFF);
80b56e972bSMiguel Aguilar 		break;
81b56e972bSMiguel Aguilar 	}
82b56e972bSMiguel Aguilar 
83b56e972bSMiguel Aguilar 	return 0;
84b56e972bSMiguel Aguilar }
85b56e972bSMiguel Aguilar 
86b56e972bSMiguel Aguilar #define CQ93VC_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
87b56e972bSMiguel Aguilar #define CQ93VC_FORMATS	(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
88b56e972bSMiguel Aguilar 
8985e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops cq93vc_dai_ops = {
90*54b59270SKuninori Morimoto 	.mute_stream	= cq93vc_mute,
91b56e972bSMiguel Aguilar 	.set_sysclk	= cq93vc_set_dai_sysclk,
92*54b59270SKuninori Morimoto 	.no_capture_mute = 1,
93b56e972bSMiguel Aguilar };
94b56e972bSMiguel Aguilar 
95f0fba2adSLiam Girdwood static struct snd_soc_dai_driver cq93vc_dai = {
96f0fba2adSLiam Girdwood 	.name = "cq93vc-hifi",
97b56e972bSMiguel Aguilar 	.playback = {
98b56e972bSMiguel Aguilar 		.stream_name = "Playback",
99b56e972bSMiguel Aguilar 		.channels_min = 1,
100b56e972bSMiguel Aguilar 		.channels_max = 2,
101b56e972bSMiguel Aguilar 		.rates = CQ93VC_RATES,
102b56e972bSMiguel Aguilar 		.formats = CQ93VC_FORMATS,},
103b56e972bSMiguel Aguilar 	.capture = {
104b56e972bSMiguel Aguilar 		.stream_name = "Capture",
105b56e972bSMiguel Aguilar 		.channels_min = 1,
106b56e972bSMiguel Aguilar 		.channels_max = 2,
107b56e972bSMiguel Aguilar 		.rates = CQ93VC_RATES,
108b56e972bSMiguel Aguilar 		.formats = CQ93VC_FORMATS,},
109b56e972bSMiguel Aguilar 	.ops = &cq93vc_dai_ops,
110b56e972bSMiguel Aguilar };
111b56e972bSMiguel Aguilar 
cq93vc_probe(struct snd_soc_component * component)11260e1780eSKuninori Morimoto static int cq93vc_probe(struct snd_soc_component *component)
11349101a25SXiubo Li {
11460e1780eSKuninori Morimoto 	struct davinci_vc *davinci_vc = component->dev->platform_data;
11549101a25SXiubo Li 
11660e1780eSKuninori Morimoto 	snd_soc_component_init_regmap(component, davinci_vc->regmap);
11760e1780eSKuninori Morimoto 
11860e1780eSKuninori Morimoto 	return 0;
11949101a25SXiubo Li }
12049101a25SXiubo Li 
1214f404f38SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cq93vc = {
122f0fba2adSLiam Girdwood 	.set_bias_level		= cq93vc_set_bias_level,
12360e1780eSKuninori Morimoto 	.probe			= cq93vc_probe,
1246f88063cSMark Brown 	.controls		= cq93vc_snd_controls,
1256f88063cSMark Brown 	.num_controls		= ARRAY_SIZE(cq93vc_snd_controls),
1264f404f38SKuninori Morimoto 	.idle_bias_on		= 1,
1274f404f38SKuninori Morimoto 	.use_pmdown_time	= 1,
1284f404f38SKuninori Morimoto 	.endianness		= 1,
129b56e972bSMiguel Aguilar };
130b56e972bSMiguel Aguilar 
cq93vc_platform_probe(struct platform_device * pdev)131f0fba2adSLiam Girdwood static int cq93vc_platform_probe(struct platform_device *pdev)
132b56e972bSMiguel Aguilar {
1334f404f38SKuninori Morimoto 	return devm_snd_soc_register_component(&pdev->dev,
1344f404f38SKuninori Morimoto 			&soc_component_dev_cq93vc, &cq93vc_dai, 1);
135b56e972bSMiguel Aguilar }
136b56e972bSMiguel Aguilar 
137b56e972bSMiguel Aguilar static struct platform_driver cq93vc_codec_driver = {
138b56e972bSMiguel Aguilar 	.driver = {
139f0fba2adSLiam Girdwood 			.name = "cq93vc-codec",
140b56e972bSMiguel Aguilar 	},
141f0fba2adSLiam Girdwood 
142f0fba2adSLiam Girdwood 	.probe = cq93vc_platform_probe,
143b56e972bSMiguel Aguilar };
144b56e972bSMiguel Aguilar 
1455bbcc3c0SMark Brown module_platform_driver(cq93vc_codec_driver);
146b56e972bSMiguel Aguilar 
147b56e972bSMiguel Aguilar MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC CQ0093 Voice Codec Driver");
148b56e972bSMiguel Aguilar MODULE_AUTHOR("Miguel Aguilar");
149b56e972bSMiguel Aguilar MODULE_LICENSE("GPL");
150