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
:
92 case SNDRV_PCM_FORMAT_S16_LE
:
96 case SNDRV_PCM_FORMAT_S24_LE
:
100 case SNDRV_PCM_FORMAT_S32_LE
:
101 param
.spctl
|= 0x1f0;
106 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
107 ret
= sport_set_tx_params(sport
, ¶m
);
109 dev_err(dev
, "SPORT tx is busy!\n");
113 ret
= sport_set_rx_params(sport
, ¶m
);
115 dev_err(dev
, "SPORT rx is busy!\n");
123 static int bfin_i2s_suspend(struct snd_soc_dai
*dai
)
125 struct sport_device
*sport
= snd_soc_dai_get_drvdata(dai
);
127 if (dai
->capture_active
)
128 sport_rx_stop(sport
);
129 if (dai
->playback_active
)
130 sport_tx_stop(sport
);
134 static int bfin_i2s_resume(struct snd_soc_dai
*dai
)
136 struct sport_device
*sport
= snd_soc_dai_get_drvdata(dai
);
137 struct device
*dev
= &sport
->pdev
->dev
;
140 ret
= sport_set_tx_params(sport
, ¶m
);
142 dev_err(dev
, "SPORT tx is busy!\n");
145 ret
= sport_set_rx_params(sport
, ¶m
);
147 dev_err(dev
, "SPORT rx is busy!\n");
155 #define bfin_i2s_suspend NULL
156 #define bfin_i2s_resume NULL
159 #define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
160 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
161 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
162 SNDRV_PCM_RATE_96000)
164 #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
165 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
167 static struct snd_soc_dai_ops bfin_i2s_dai_ops
= {
168 .hw_params
= bfin_i2s_hw_params
,
169 .set_fmt
= bfin_i2s_set_dai_fmt
,
172 static struct snd_soc_dai_driver bfin_i2s_dai
= {
173 .suspend
= bfin_i2s_suspend
,
174 .resume
= bfin_i2s_resume
,
178 .rates
= BFIN_I2S_RATES
,
179 .formats
= BFIN_I2S_FORMATS
,
184 .rates
= BFIN_I2S_RATES
,
185 .formats
= BFIN_I2S_FORMATS
,
187 .ops
= &bfin_i2s_dai_ops
,
190 static const struct snd_soc_component_driver bfin_i2s_component
= {
194 static int bfin_i2s_probe(struct platform_device
*pdev
)
196 struct sport_device
*sport
;
197 struct device
*dev
= &pdev
->dev
;
200 sport
= sport_create(pdev
);
204 /* register with the ASoC layers */
205 ret
= snd_soc_register_component(dev
, &bfin_i2s_component
,
208 dev_err(dev
, "Failed to register DAI: %d\n", ret
);
212 platform_set_drvdata(pdev
, sport
);
217 static int bfin_i2s_remove(struct platform_device
*pdev
)
219 struct sport_device
*sport
= platform_get_drvdata(pdev
);
221 snd_soc_unregister_component(&pdev
->dev
);
227 static struct platform_driver bfin_i2s_driver
= {
228 .probe
= bfin_i2s_probe
,
229 .remove
= bfin_i2s_remove
,
232 .owner
= THIS_MODULE
,
236 module_platform_driver(bfin_i2s_driver
);
238 MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver");
239 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
240 MODULE_LICENSE("GPL v2");