2 * mx27vis_wm8974.c -- SoC audio for mx27vis
4 * Copyright 2009 Vista Silicon S.L.
5 * Author: Javier Martin
6 * javier.martin@vista-silicon.com
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/device.h>
18 #include <linux/i2c.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/soc.h>
22 #include <sound/soc-dapm.h>
25 #include "../codecs/wm8974.h"
26 #include "mx1_mx2-pcm.h"
28 #include <mach/gpio.h>
29 #include <mach/iomux.h>
34 static struct snd_soc_card mx27vis
;
37 * This function connects SSI1 (HPCR1) as slave to
38 * SSI1 external signals (PPCR1)
39 * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from
42 void audmux_connect_1_4(void)
44 pr_debug("AUDMUX: normal operation mode\n");
45 /* Reset HPCR1 and PPCR1 */
47 DAM_HPCR1
= 0x00000000;
48 DAM_PPCR1
= 0x00000000;
50 /* set to synchronous */
51 DAM_HPCR1
|= AUDMUX_HPCR_SYN
;
52 DAM_PPCR1
|= AUDMUX_PPCR_SYN
;
55 /* set Rx sources 1 <--> 4 */
56 DAM_HPCR1
|= AUDMUX_HPCR_RXDSEL(3); /* port 4 */
57 DAM_PPCR1
|= AUDMUX_PPCR_RXDSEL(0); /* port 1 */
59 /* set Tx frame and Clock direction and source 4 --> 1 output */
60 DAM_HPCR1
|= AUDMUX_HPCR_TFSDIR
| AUDMUX_HPCR_TCLKDIR
;
61 DAM_HPCR1
|= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */
66 static int mx27vis_hifi_hw_params(struct snd_pcm_substream
*substream
,
67 struct snd_pcm_hw_params
*params
)
69 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
70 struct snd_soc_dai
*codec_dai
= rtd
->dai
->codec_dai
;
71 struct snd_soc_dai
*cpu_dai
= rtd
->dai
->cpu_dai
;
72 unsigned int pll_out
= 0, bclk
= 0, fmt
= 0, mclk
= 0;
76 * The WM8974 is better at generating accurate audio clocks than the
77 * MX27 SSI controller, so we will use it as master when we can.
79 switch (params_rate(params
)) {
81 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
82 mclk
= WM8974_MCLKDIV_12
;
86 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
90 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
91 bclk
= WM8974_BCLKDIV_4
;
95 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
96 bclk
= WM8974_BCLKDIV_2
;
100 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
101 bclk
= WM8974_BCLKDIV_16
;
105 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
106 bclk
= WM8974_BCLKDIV_8
;
110 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
111 bclk
= WM8974_BCLKDIV_4
;
112 mclk
= WM8974_MCLKDIV_2
;
116 fmt
= SND_SOC_DAIFMT_CBM_CFM
;
117 bclk
= WM8974_BCLKDIV_2
;
122 /* set codec DAI configuration */
123 ret
= codec_dai
->ops
->set_fmt(codec_dai
,
124 SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_IF
|
125 SND_SOC_DAIFMT_SYNC
| fmt
);
127 printk(KERN_ERR
"Error from codec DAI configuration\n");
131 /* set cpu DAI configuration */
132 ret
= cpu_dai
->ops
->set_fmt(cpu_dai
,
133 SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
134 SND_SOC_DAIFMT_SYNC
| fmt
);
136 printk(KERN_ERR
"Error from cpu DAI configuration\n");
140 /* Put DC field of STCCR to 1 (not zero) */
141 ret
= cpu_dai
->ops
->set_tdm_slot(cpu_dai
, 0, 2);
143 /* set the SSI system clock as input */
144 ret
= cpu_dai
->ops
->set_sysclk(cpu_dai
, IMX_SSP_SYS_CLK
, 0,
147 printk(KERN_ERR
"Error when setting system SSI clk\n");
151 /* set codec BCLK division for sample rate */
152 ret
= codec_dai
->ops
->set_clkdiv(codec_dai
, WM8974_BCLKDIV
, bclk
);
154 printk(KERN_ERR
"Error when setting BCLK division\n");
159 /* codec PLL input is 25 MHz */
160 ret
= codec_dai
->ops
->set_pll(codec_dai
, IGNORED_ARG
, IGNORED_ARG
,
163 printk(KERN_ERR
"Error when setting PLL input\n");
167 /*set codec MCLK division for sample rate */
168 ret
= codec_dai
->ops
->set_clkdiv(codec_dai
, WM8974_MCLKDIV
, mclk
);
170 printk(KERN_ERR
"Error when setting MCLK division\n");
177 static int mx27vis_hifi_hw_free(struct snd_pcm_substream
*substream
)
179 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
180 struct snd_soc_dai
*codec_dai
= rtd
->dai
->codec_dai
;
182 /* disable the PLL */
183 return codec_dai
->ops
->set_pll(codec_dai
, IGNORED_ARG
, IGNORED_ARG
,
188 * mx27vis WM8974 HiFi DAI opserations.
190 static struct snd_soc_ops mx27vis_hifi_ops
= {
191 .hw_params
= mx27vis_hifi_hw_params
,
192 .hw_free
= mx27vis_hifi_hw_free
,
196 static int mx27vis_suspend(struct platform_device
*pdev
, pm_message_t state
)
201 static int mx27vis_resume(struct platform_device
*pdev
)
206 static int mx27vis_probe(struct platform_device
*pdev
)
210 ret
= get_ssi_clk(0, &pdev
->dev
);
213 printk(KERN_ERR
"%s: cant get ssi clock\n", __func__
);
221 static int mx27vis_remove(struct platform_device
*pdev
)
227 static struct snd_soc_dai_link mx27vis_dai
[] = {
230 .stream_name
= "WM8974 HiFi",
231 .cpu_dai
= &imx_ssi_pcm_dai
[0],
232 .codec_dai
= &wm8974_dai
,
233 .ops
= &mx27vis_hifi_ops
,
237 static struct snd_soc_card mx27vis
= {
239 .platform
= &mx1_mx2_soc_platform
,
240 .probe
= mx27vis_probe
,
241 .remove
= mx27vis_remove
,
242 .suspend_pre
= mx27vis_suspend
,
243 .resume_post
= mx27vis_resume
,
244 .dai_link
= mx27vis_dai
,
245 .num_links
= ARRAY_SIZE(mx27vis_dai
),
248 static struct snd_soc_device mx27vis_snd_devdata
= {
250 .codec_dev
= &soc_codec_dev_wm8974
,
253 static struct platform_device
*mx27vis_snd_device
;
255 /* Temporal definition of board specific behaviour */
256 void gpio_ssi_active(int ssi_num
)
260 unsigned int ssi1_pins
[] = {
266 unsigned int ssi2_pins
[] = {
273 ret
= mxc_gpio_setup_multiple_pins(ssi1_pins
,
274 ARRAY_SIZE(ssi1_pins
), "USB OTG");
276 ret
= mxc_gpio_setup_multiple_pins(ssi2_pins
,
277 ARRAY_SIZE(ssi2_pins
), "USB OTG");
279 printk(KERN_ERR
"Error requesting ssi %x pins\n", ssi_num
);
283 static int __init
mx27vis_init(void)
287 mx27vis_snd_device
= platform_device_alloc("soc-audio", -1);
288 if (!mx27vis_snd_device
)
291 platform_set_drvdata(mx27vis_snd_device
, &mx27vis_snd_devdata
);
292 mx27vis_snd_devdata
.dev
= &mx27vis_snd_device
->dev
;
293 ret
= platform_device_add(mx27vis_snd_device
);
296 printk(KERN_ERR
"ASoC: Platform device allocation failed\n");
297 platform_device_put(mx27vis_snd_device
);
300 /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */
302 audmux_connect_1_4();
307 static void __exit
mx27vis_exit(void)
309 /* We should call some "ssi_gpio_inactive()" properly */
312 module_init(mx27vis_init
);
313 module_exit(mx27vis_exit
);
316 MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com");
317 MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis");
318 MODULE_LICENSE("GPL");