2 * mt2701-wm8960.c -- MT2701 WM8960 ALSA SoC machine driver
4 * Copyright (c) 2017 MediaTek Inc.
5 * Author: Ryder Lee <ryder.lee@mediatek.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 and
9 * only version 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/module.h>
18 #include <sound/soc.h>
20 #include "mt2701-afe-common.h"
22 static const struct snd_soc_dapm_widget mt2701_wm8960_widgets
[] = {
23 SND_SOC_DAPM_HP("Headphone", NULL
),
24 SND_SOC_DAPM_MIC("AMIC", NULL
),
27 static const struct snd_kcontrol_new mt2701_wm8960_controls
[] = {
28 SOC_DAPM_PIN_SWITCH("Headphone"),
29 SOC_DAPM_PIN_SWITCH("AMIC"),
32 static int mt2701_wm8960_be_ops_hw_params(struct snd_pcm_substream
*substream
,
33 struct snd_pcm_hw_params
*params
)
35 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
36 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
37 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
38 unsigned int mclk_rate
;
39 unsigned int rate
= params_rate(params
);
40 unsigned int div_mclk_over_bck
= rate
> 192000 ? 2 : 4;
41 unsigned int div_bck_over_lrck
= 64;
43 mclk_rate
= rate
* div_bck_over_lrck
* div_mclk_over_bck
;
45 snd_soc_dai_set_sysclk(cpu_dai
, 0, mclk_rate
, SND_SOC_CLOCK_OUT
);
46 snd_soc_dai_set_sysclk(codec_dai
, 0, mclk_rate
, SND_SOC_CLOCK_IN
);
51 static struct snd_soc_ops mt2701_wm8960_be_ops
= {
52 .hw_params
= mt2701_wm8960_be_ops_hw_params
55 static struct snd_soc_dai_link mt2701_wm8960_dai_links
[] = {
58 .name
= "wm8960-playback",
59 .stream_name
= "wm8960-playback",
60 .cpu_dai_name
= "PCMO0",
61 .codec_name
= "snd-soc-dummy",
62 .codec_dai_name
= "snd-soc-dummy-dai",
63 .trigger
= {SND_SOC_DPCM_TRIGGER_POST
,
64 SND_SOC_DPCM_TRIGGER_POST
},
69 .name
= "wm8960-capture",
70 .stream_name
= "wm8960-capture",
71 .cpu_dai_name
= "PCM0",
72 .codec_name
= "snd-soc-dummy",
73 .codec_dai_name
= "snd-soc-dummy-dai",
74 .trigger
= {SND_SOC_DPCM_TRIGGER_POST
,
75 SND_SOC_DPCM_TRIGGER_POST
},
81 .name
= "wm8960-codec",
82 .cpu_dai_name
= "I2S0",
84 .codec_dai_name
= "wm8960-hifi",
85 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_CBS_CFS
86 | SND_SOC_DAIFMT_GATED
,
87 .ops
= &mt2701_wm8960_be_ops
,
93 static struct snd_soc_card mt2701_wm8960_card
= {
94 .name
= "mt2701-wm8960",
96 .dai_link
= mt2701_wm8960_dai_links
,
97 .num_links
= ARRAY_SIZE(mt2701_wm8960_dai_links
),
98 .controls
= mt2701_wm8960_controls
,
99 .num_controls
= ARRAY_SIZE(mt2701_wm8960_controls
),
100 .dapm_widgets
= mt2701_wm8960_widgets
,
101 .num_dapm_widgets
= ARRAY_SIZE(mt2701_wm8960_widgets
),
104 static int mt2701_wm8960_machine_probe(struct platform_device
*pdev
)
106 struct snd_soc_card
*card
= &mt2701_wm8960_card
;
107 struct device_node
*platform_node
, *codec_node
;
110 platform_node
= of_parse_phandle(pdev
->dev
.of_node
,
111 "mediatek,platform", 0);
112 if (!platform_node
) {
113 dev_err(&pdev
->dev
, "Property 'platform' missing or invalid\n");
116 for (i
= 0; i
< card
->num_links
; i
++) {
117 if (mt2701_wm8960_dai_links
[i
].platform_name
)
119 mt2701_wm8960_dai_links
[i
].platform_of_node
= platform_node
;
122 card
->dev
= &pdev
->dev
;
124 codec_node
= of_parse_phandle(pdev
->dev
.of_node
,
125 "mediatek,audio-codec", 0);
128 "Property 'audio-codec' missing or invalid\n");
131 for (i
= 0; i
< card
->num_links
; i
++) {
132 if (mt2701_wm8960_dai_links
[i
].codec_name
)
134 mt2701_wm8960_dai_links
[i
].codec_of_node
= codec_node
;
137 ret
= snd_soc_of_parse_audio_routing(card
, "audio-routing");
139 dev_err(&pdev
->dev
, "failed to parse audio-routing: %d\n", ret
);
143 ret
= devm_snd_soc_register_card(&pdev
->dev
, card
);
145 dev_err(&pdev
->dev
, "%s snd_soc_register_card fail %d\n",
152 static const struct of_device_id mt2701_wm8960_machine_dt_match
[] = {
153 {.compatible
= "mediatek,mt2701-wm8960-machine",},
158 static struct platform_driver mt2701_wm8960_machine
= {
160 .name
= "mt2701-wm8960",
161 .owner
= THIS_MODULE
,
163 .of_match_table
= mt2701_wm8960_machine_dt_match
,
166 .probe
= mt2701_wm8960_machine_probe
,
169 module_platform_driver(mt2701_wm8960_machine
);
171 /* Module information */
172 MODULE_DESCRIPTION("MT2701 WM8960 ALSA SoC machine driver");
173 MODULE_AUTHOR("Ryder Lee <ryder.lee@mediatek.com>");
174 MODULE_LICENSE("GPL v2");
175 MODULE_ALIAS("mt2701 wm8960 soc card");