2 * bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver
4 * Copyright (c) 2012 Analog Devices Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <linux/device.h>
21 #include <linux/init.h>
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
27 #include <sound/soc-dai.h>
29 #include "bf6xx-sport.h"
31 struct sport_params param
;
33 static int bfin_i2s_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
36 struct sport_device
*sport
= snd_soc_dai_get_drvdata(cpu_dai
);
37 struct device
*dev
= &sport
->pdev
->dev
;
40 param
.spctl
&= ~(SPORT_CTL_OPMODE
| SPORT_CTL_CKRE
| SPORT_CTL_FSR
41 | SPORT_CTL_LFS
| SPORT_CTL_LAFS
);
42 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
43 case SND_SOC_DAIFMT_I2S
:
44 param
.spctl
|= SPORT_CTL_OPMODE
| SPORT_CTL_CKRE
47 case SND_SOC_DAIFMT_DSP_A
:
48 param
.spctl
|= SPORT_CTL_FSR
;
50 case SND_SOC_DAIFMT_LEFT_J
:
51 param
.spctl
|= SPORT_CTL_OPMODE
| SPORT_CTL_LFS
55 dev_err(dev
, "%s: Unknown DAI format type\n", __func__
);
60 param
.spctl
&= ~(SPORT_CTL_ICLK
| SPORT_CTL_IFS
);
61 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
62 case SND_SOC_DAIFMT_CBM_CFM
:
64 case SND_SOC_DAIFMT_CBS_CFS
:
65 case SND_SOC_DAIFMT_CBM_CFS
:
66 case SND_SOC_DAIFMT_CBS_CFM
:
70 dev_err(dev
, "%s: Unknown DAI master type\n", __func__
);
78 static int bfin_i2s_hw_params(struct snd_pcm_substream
*substream
,
79 struct snd_pcm_hw_params
*params
,
80 struct snd_soc_dai
*dai
)
82 struct sport_device
*sport
= snd_soc_dai_get_drvdata(dai
);
83 struct device
*dev
= &sport
->pdev
->dev
;
86 param
.spctl
&= ~SPORT_CTL_SLEN
;
87 switch (params_format(params
)) {
88 case SNDRV_PCM_FORMAT_S8
:
91 case SNDRV_PCM_FORMAT_S16_LE
:
95 case SNDRV_PCM_FORMAT_S24_LE
:
99 case SNDRV_PCM_FORMAT_S32_LE
:
100 param
.spctl
|= 0x1f0;
105 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
106 ret
= sport_set_tx_params(sport
, ¶m
);
108 dev_err(dev
, "SPORT tx is busy!\n");
112 ret
= sport_set_rx_params(sport
, ¶m
);
114 dev_err(dev
, "SPORT rx is busy!\n");
122 static int bfin_i2s_suspend(struct snd_soc_dai
*dai
)
124 struct sport_device
*sport
= snd_soc_dai_get_drvdata(dai
);
126 if (dai
->capture_active
)
127 sport_rx_stop(sport
);
128 if (dai
->playback_active
)
129 sport_tx_stop(sport
);
133 static int bfin_i2s_resume(struct snd_soc_dai
*dai
)
135 struct sport_device
*sport
= snd_soc_dai_get_drvdata(dai
);
136 struct device
*dev
= &sport
->pdev
->dev
;
139 ret
= sport_set_tx_params(sport
, ¶m
);
141 dev_err(dev
, "SPORT tx is busy!\n");
144 ret
= sport_set_rx_params(sport
, ¶m
);
146 dev_err(dev
, "SPORT rx is busy!\n");
154 #define bfin_i2s_suspend NULL
155 #define bfin_i2s_resume NULL
158 #define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
159 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
160 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
161 SNDRV_PCM_RATE_96000)
163 #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
164 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
166 static struct snd_soc_dai_ops bfin_i2s_dai_ops
= {
167 .hw_params
= bfin_i2s_hw_params
,
168 .set_fmt
= bfin_i2s_set_dai_fmt
,
171 static struct snd_soc_dai_driver bfin_i2s_dai
= {
172 .suspend
= bfin_i2s_suspend
,
173 .resume
= bfin_i2s_resume
,
177 .rates
= BFIN_I2S_RATES
,
178 .formats
= BFIN_I2S_FORMATS
,
183 .rates
= BFIN_I2S_RATES
,
184 .formats
= BFIN_I2S_FORMATS
,
186 .ops
= &bfin_i2s_dai_ops
,
189 static int bfin_i2s_probe(struct platform_device
*pdev
)
191 struct sport_device
*sport
;
192 struct device
*dev
= &pdev
->dev
;
195 sport
= sport_create(pdev
);
199 /* register with the ASoC layers */
200 ret
= snd_soc_register_dai(dev
, &bfin_i2s_dai
);
202 dev_err(dev
, "Failed to register DAI: %d\n", ret
);
206 platform_set_drvdata(pdev
, sport
);
211 static int bfin_i2s_remove(struct platform_device
*pdev
)
213 struct sport_device
*sport
= platform_get_drvdata(pdev
);
215 snd_soc_unregister_dai(&pdev
->dev
);
221 static struct platform_driver bfin_i2s_driver
= {
222 .probe
= bfin_i2s_probe
,
223 .remove
= bfin_i2s_remove
,
226 .owner
= THIS_MODULE
,
230 module_platform_driver(bfin_i2s_driver
);
232 MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
233 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
234 MODULE_LICENSE("GPL v2");