1 // SPDX-License-Identifier: GPL-2.0-only
3 * ASoC driver for PROTO AudioCODEC (with a WM8731)
5 * Author: Florian Meier, <koalo@koalo.de>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
12 #include <sound/core.h>
13 #include <sound/pcm.h>
14 #include <sound/soc.h>
15 #include <sound/jack.h>
17 #include "../codecs/wm8731.h"
19 #define XTAL_RATE 12288000 /* This is fixed on this board */
21 static int snd_proto_init(struct snd_soc_pcm_runtime
*rtd
)
23 struct snd_soc_card
*card
= rtd
->card
;
24 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
26 /* Set proto sysclk */
27 int ret
= snd_soc_dai_set_sysclk(codec_dai
, WM8731_SYSCLK_XTAL
,
28 XTAL_RATE
, SND_SOC_CLOCK_IN
);
30 dev_err(card
->dev
, "Failed to set WM8731 SYSCLK: %d\n",
38 static const struct snd_soc_dapm_widget snd_proto_widget
[] = {
39 SND_SOC_DAPM_MIC("Microphone Jack", NULL
),
40 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
43 static const struct snd_soc_dapm_route snd_proto_route
[] = {
44 /* speaker connected to LHPOUT/RHPOUT */
45 {"Headphone Jack", NULL
, "LHPOUT"},
46 {"Headphone Jack", NULL
, "RHPOUT"},
48 /* mic is connected to Mic Jack, with WM8731 Mic Bias */
49 {"MICIN", NULL
, "Mic Bias"},
50 {"Mic Bias", NULL
, "Microphone Jack"},
53 /* audio machine driver */
54 static struct snd_soc_card snd_proto
= {
55 .name
= "snd_mikroe_proto",
57 .dapm_widgets
= snd_proto_widget
,
58 .num_dapm_widgets
= ARRAY_SIZE(snd_proto_widget
),
59 .dapm_routes
= snd_proto_route
,
60 .num_dapm_routes
= ARRAY_SIZE(snd_proto_route
),
63 static int snd_proto_probe(struct platform_device
*pdev
)
65 struct snd_soc_dai_link
*dai
;
66 struct snd_soc_dai_link_component
*comp
;
67 struct device_node
*np
= pdev
->dev
.of_node
;
68 struct device_node
*codec_np
, *cpu_np
;
69 struct device_node
*bitclkmaster
= NULL
;
70 struct device_node
*framemaster
= NULL
;
75 dev_err(&pdev
->dev
, "No device node supplied\n");
79 snd_proto
.dev
= &pdev
->dev
;
80 ret
= snd_soc_of_parse_card_name(&snd_proto
, "model");
84 dai
= devm_kzalloc(&pdev
->dev
, sizeof(*dai
), GFP_KERNEL
);
88 /* for cpus/codecs/platforms */
89 comp
= devm_kzalloc(&pdev
->dev
, 3 * sizeof(*comp
), GFP_KERNEL
);
93 snd_proto
.dai_link
= dai
;
94 snd_proto
.num_links
= 1;
98 dai
->codecs
= &comp
[1];
100 dai
->platforms
= &comp
[2];
101 dai
->num_platforms
= 1;
103 dai
->name
= "WM8731";
104 dai
->stream_name
= "WM8731 HiFi";
105 dai
->codecs
->dai_name
= "wm8731-hifi";
106 dai
->init
= &snd_proto_init
;
108 codec_np
= of_parse_phandle(np
, "audio-codec", 0);
110 dev_err(&pdev
->dev
, "audio-codec node missing\n");
113 dai
->codecs
->of_node
= codec_np
;
115 cpu_np
= of_parse_phandle(np
, "i2s-controller", 0);
117 dev_err(&pdev
->dev
, "i2s-controller missing\n");
121 dai
->cpus
->of_node
= cpu_np
;
122 dai
->platforms
->of_node
= cpu_np
;
124 dai_fmt
= snd_soc_daifmt_parse_format(np
, NULL
);
125 snd_soc_daifmt_parse_clock_provider_as_phandle(np
, NULL
,
126 &bitclkmaster
, &framemaster
);
127 if (bitclkmaster
!= framemaster
) {
128 dev_err(&pdev
->dev
, "Must be the same bitclock and frame master\n");
133 if (codec_np
== bitclkmaster
)
134 dai_fmt
|= SND_SOC_DAIFMT_CBP_CFP
;
136 dai_fmt
|= SND_SOC_DAIFMT_CBC_CFC
;
138 dai_fmt
|= snd_soc_daifmt_parse_clock_provider_as_flag(np
, NULL
);
142 dai
->dai_fmt
= dai_fmt
;
143 ret
= devm_snd_soc_register_card(&pdev
->dev
, &snd_proto
);
145 dev_err_probe(&pdev
->dev
, ret
,
146 "snd_soc_register_card() failed\n");
150 of_node_put(bitclkmaster
);
151 of_node_put(framemaster
);
154 of_node_put(codec_np
);
158 static const struct of_device_id snd_proto_of_match
[] = {
159 { .compatible
= "mikroe,mikroe-proto", },
162 MODULE_DEVICE_TABLE(of
, snd_proto_of_match
);
164 static struct platform_driver snd_proto_driver
= {
166 .name
= "snd-mikroe-proto",
167 .of_match_table
= snd_proto_of_match
,
169 .probe
= snd_proto_probe
,
172 module_platform_driver(snd_proto_driver
);
174 MODULE_AUTHOR("Florian Meier");
175 MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
176 MODULE_LICENSE("GPL");