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
= rtd
->codec_dai
;
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");
120 dai
->cpus
->of_node
= cpu_np
;
121 dai
->platforms
->of_node
= cpu_np
;
123 dai_fmt
= snd_soc_of_parse_daifmt(np
, NULL
,
124 &bitclkmaster
, &framemaster
);
125 if (bitclkmaster
!= framemaster
) {
126 dev_err(&pdev
->dev
, "Must be the same bitclock and frame master\n");
130 dai_fmt
&= ~SND_SOC_DAIFMT_MASTER_MASK
;
131 if (codec_np
== bitclkmaster
)
132 dai_fmt
|= SND_SOC_DAIFMT_CBM_CFM
;
134 dai_fmt
|= SND_SOC_DAIFMT_CBS_CFS
;
136 of_node_put(bitclkmaster
);
137 of_node_put(framemaster
);
138 dai
->dai_fmt
= dai_fmt
;
140 of_node_put(codec_np
);
143 ret
= snd_soc_register_card(&snd_proto
);
144 if (ret
&& ret
!= -EPROBE_DEFER
)
146 "snd_soc_register_card() failed: %d\n", ret
);
151 static int snd_proto_remove(struct platform_device
*pdev
)
153 return snd_soc_unregister_card(&snd_proto
);
156 static const struct of_device_id snd_proto_of_match
[] = {
157 { .compatible
= "mikroe,mikroe-proto", },
160 MODULE_DEVICE_TABLE(of
, snd_proto_of_match
);
162 static struct platform_driver snd_proto_driver
= {
164 .name
= "snd-mikroe-proto",
165 .of_match_table
= snd_proto_of_match
,
167 .probe
= snd_proto_probe
,
168 .remove
= snd_proto_remove
,
171 module_platform_driver(snd_proto_driver
);
173 MODULE_AUTHOR("Florian Meier");
174 MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
175 MODULE_LICENSE("GPL");