]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - sound/soc/rockchip/rockchip_rt5645.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / sound / soc / rockchip / rockchip_rt5645.c
CommitLineData
9952f691 1// SPDX-License-Identifier: GPL-2.0-only
86059653 2/*
3 * Rockchip machine ASoC driver for boards using a RT5645/RT5650 CODEC.
4 *
5 * Copyright (c) 2015, ROCKCHIP CORPORATION. All rights reserved.
86059653 6 */
7
8#include <linux/module.h>
9#include <linux/platform_device.h>
10#include <linux/slab.h>
11#include <linux/gpio.h>
12#include <linux/of_gpio.h>
13#include <linux/delay.h>
14#include <sound/core.h>
15#include <sound/jack.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include "rockchip_i2s.h"
79223bf1 20#include "../codecs/rt5645.h"
86059653 21
22#define DRV_NAME "rockchip-snd-rt5645"
23
24static struct snd_soc_jack headset_jack;
25
86059653 26static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
27 SND_SOC_DAPM_HP("Headphones", NULL),
28 SND_SOC_DAPM_SPK("Speakers", NULL),
29 SND_SOC_DAPM_MIC("Headset Mic", NULL),
30 SND_SOC_DAPM_MIC("Int Mic", NULL),
31};
32
33static const struct snd_soc_dapm_route rk_audio_map[] = {
34 /* Input Lines */
35 {"DMIC L2", NULL, "Int Mic"},
36 {"DMIC R2", NULL, "Int Mic"},
37 {"RECMIXL", NULL, "Headset Mic"},
38 {"RECMIXR", NULL, "Headset Mic"},
39
40 /* Output Lines */
41 {"Headphones", NULL, "HPOR"},
42 {"Headphones", NULL, "HPOL"},
43 {"Speakers", NULL, "SPOL"},
44 {"Speakers", NULL, "SPOR"},
45};
46
47static const struct snd_kcontrol_new rk_mc_controls[] = {
48 SOC_DAPM_PIN_SWITCH("Headphones"),
49 SOC_DAPM_PIN_SWITCH("Speakers"),
50 SOC_DAPM_PIN_SWITCH("Headset Mic"),
51 SOC_DAPM_PIN_SWITCH("Int Mic"),
52};
53
54static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
55 struct snd_pcm_hw_params *params)
56{
57 int ret = 0;
58 struct snd_soc_pcm_runtime *rtd = substream->private_data;
59 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
60 struct snd_soc_dai *codec_dai = rtd->codec_dai;
61 int mclk;
62
63 switch (params_rate(params)) {
64 case 8000:
65 case 16000:
3a3b070d
CW
66 case 24000:
67 case 32000:
86059653 68 case 48000:
3a3b070d 69 case 64000:
86059653 70 case 96000:
71 mclk = 12288000;
72 break;
3a3b070d
CW
73 case 11025:
74 case 22050:
86059653 75 case 44100:
3a3b070d 76 case 88200:
86059653 77 mclk = 11289600;
78 break;
79 default:
80 return -EINVAL;
81 }
82
83 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
84 SND_SOC_CLOCK_OUT);
85 if (ret < 0) {
86 dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
87 return ret;
88 }
89
90 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
91 SND_SOC_CLOCK_IN);
92 if (ret < 0) {
93 dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret);
94 return ret;
95 }
96
97 return ret;
98}
99
100static int rk_init(struct snd_soc_pcm_runtime *runtime)
101{
102 struct snd_soc_card *card = runtime->card;
103 int ret;
104
105 /* Enable Headset and 4 Buttons Jack detection */
106 ret = snd_soc_card_jack_new(card, "Headset Jack",
107 SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
108 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
109 SND_JACK_BTN_2 | SND_JACK_BTN_3,
110 &headset_jack, NULL, 0);
f8ce2000 111 if (ret) {
86059653 112 dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
113 return ret;
114 }
115
79223bf1 116 return rt5645_set_jack_detect(runtime->codec_dai->component,
86059653 117 &headset_jack,
118 &headset_jack,
119 &headset_jack);
120}
121
705e9994 122static const struct snd_soc_ops rk_aif1_ops = {
86059653 123 .hw_params = rk_aif1_hw_params,
124};
125
126static struct snd_soc_dai_link rk_dailink = {
127 .name = "rt5645",
128 .stream_name = "rt5645 PCM",
129 .codec_dai_name = "rt5645-aif1",
130 .init = rk_init,
131 .ops = &rk_aif1_ops,
132 /* set rt5645 as slave */
133 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
134 SND_SOC_DAIFMT_CBS_CFS,
135};
136
137static struct snd_soc_card snd_soc_card_rk = {
138 .name = "I2S-RT5650",
54d8697f 139 .owner = THIS_MODULE,
86059653 140 .dai_link = &rk_dailink,
141 .num_links = 1,
142 .dapm_widgets = rk_dapm_widgets,
143 .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets),
144 .dapm_routes = rk_audio_map,
145 .num_dapm_routes = ARRAY_SIZE(rk_audio_map),
146 .controls = rk_mc_controls,
147 .num_controls = ARRAY_SIZE(rk_mc_controls),
148};
149
150static int snd_rk_mc_probe(struct platform_device *pdev)
151{
152 int ret = 0;
153 struct snd_soc_card *card = &snd_soc_card_rk;
154 struct device_node *np = pdev->dev.of_node;
155
156 /* register the soc card */
157 card->dev = &pdev->dev;
158
159 rk_dailink.codec_of_node = of_parse_phandle(np,
160 "rockchip,audio-codec", 0);
161 if (!rk_dailink.codec_of_node) {
162 dev_err(&pdev->dev,
163 "Property 'rockchip,audio-codec' missing or invalid\n");
164 return -EINVAL;
165 }
166
167 rk_dailink.cpu_of_node = of_parse_phandle(np,
168 "rockchip,i2s-controller", 0);
169 if (!rk_dailink.cpu_of_node) {
170 dev_err(&pdev->dev,
171 "Property 'rockchip,i2s-controller' missing or invalid\n");
a56df73b
AK
172 ret = -EINVAL;
173 goto put_codec_of_node;
86059653 174 }
175
176 rk_dailink.platform_of_node = rk_dailink.cpu_of_node;
177
178 ret = snd_soc_of_parse_card_name(card, "rockchip,model");
179 if (ret) {
180 dev_err(&pdev->dev,
181 "Soc parse card name failed %d\n", ret);
a56df73b 182 goto put_cpu_of_node;
86059653 183 }
184
185 ret = devm_snd_soc_register_card(&pdev->dev, card);
186 if (ret) {
187 dev_err(&pdev->dev,
188 "Soc register card failed %d\n", ret);
a56df73b 189 goto put_cpu_of_node;
86059653 190 }
191
192 return ret;
a56df73b
AK
193
194put_cpu_of_node:
195 of_node_put(rk_dailink.cpu_of_node);
196 rk_dailink.cpu_of_node = NULL;
197put_codec_of_node:
198 of_node_put(rk_dailink.codec_of_node);
199 rk_dailink.codec_of_node = NULL;
200
201 return ret;
202}
203
204static int snd_rk_mc_remove(struct platform_device *pdev)
205{
206 of_node_put(rk_dailink.cpu_of_node);
207 rk_dailink.cpu_of_node = NULL;
208 of_node_put(rk_dailink.codec_of_node);
209 rk_dailink.codec_of_node = NULL;
210
211 return 0;
86059653 212}
213
214static const struct of_device_id rockchip_rt5645_of_match[] = {
215 { .compatible = "rockchip,rockchip-audio-rt5645", },
216 {},
217};
218
219MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match);
220
221static struct platform_driver snd_rk_mc_driver = {
222 .probe = snd_rk_mc_probe,
a56df73b 223 .remove = snd_rk_mc_remove,
86059653 224 .driver = {
225 .name = DRV_NAME,
86059653 226 .pm = &snd_soc_pm_ops,
227 .of_match_table = rockchip_rt5645_of_match,
228 },
229};
230
231module_platform_driver(snd_rk_mc_driver);
232
233MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
234MODULE_DESCRIPTION("Rockchip rt5645 machine ASoC driver");
235MODULE_LICENSE("GPL v2");
236MODULE_ALIAS("platform:" DRV_NAME);