diff options
Diffstat (limited to 'sound/soc/blackfin/bf5xx-i2s.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s.c | 69 |
1 files changed, 49 insertions, 20 deletions
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 43a4092eeb89..e020c160ee44 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -70,6 +70,25 @@ static struct sport_param sport_params[2] = { | |||
70 | } | 70 | } |
71 | }; | 71 | }; |
72 | 72 | ||
73 | /* | ||
74 | * Setting the TFS pin selector for SPORT 0 based on whether the selected | ||
75 | * port id F or G. If the port is F then no conflict should exist for the | ||
76 | * TFS. When Port G is selected and EMAC then there is a conflict between | ||
77 | * the PHY interrupt line and TFS. Current settings prevent the conflict | ||
78 | * by ignoring the TFS pin when Port G is selected. This allows both | ||
79 | * ssm2602 using Port G and EMAC concurrently. | ||
80 | */ | ||
81 | #ifdef CONFIG_BF527_SPORT0_PORTF | ||
82 | #define LOCAL_SPORT0_TFS (P_SPORT0_TFS) | ||
83 | #else | ||
84 | #define LOCAL_SPORT0_TFS (0) | ||
85 | #endif | ||
86 | |||
87 | static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
88 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, | ||
89 | {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, | ||
90 | P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; | ||
91 | |||
73 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 92 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
74 | unsigned int fmt) | 93 | unsigned int fmt) |
75 | { | 94 | { |
@@ -78,28 +97,34 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
78 | /* interface format:support I2S,slave mode */ | 97 | /* interface format:support I2S,slave mode */ |
79 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 98 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
80 | case SND_SOC_DAIFMT_I2S: | 99 | case SND_SOC_DAIFMT_I2S: |
100 | bf5xx_i2s.tcr1 |= TFSR | TCKFE; | ||
101 | bf5xx_i2s.rcr1 |= RFSR | RCKFE; | ||
102 | bf5xx_i2s.tcr2 |= TSFSE; | ||
103 | bf5xx_i2s.rcr2 |= RSFSE; | ||
104 | break; | ||
105 | case SND_SOC_DAIFMT_DSP_A: | ||
106 | bf5xx_i2s.tcr1 |= TFSR; | ||
107 | bf5xx_i2s.rcr1 |= RFSR; | ||
81 | break; | 108 | break; |
82 | case SND_SOC_DAIFMT_LEFT_J: | 109 | case SND_SOC_DAIFMT_LEFT_J: |
83 | ret = -EINVAL; | 110 | ret = -EINVAL; |
84 | break; | 111 | break; |
85 | default: | 112 | default: |
113 | printk(KERN_ERR "%s: Unknown DAI format type\n", __func__); | ||
86 | ret = -EINVAL; | 114 | ret = -EINVAL; |
87 | break; | 115 | break; |
88 | } | 116 | } |
89 | 117 | ||
90 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 118 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
91 | case SND_SOC_DAIFMT_CBS_CFS: | ||
92 | ret = -EINVAL; | ||
93 | break; | ||
94 | case SND_SOC_DAIFMT_CBM_CFS: | ||
95 | ret = -EINVAL; | ||
96 | break; | ||
97 | case SND_SOC_DAIFMT_CBM_CFM: | 119 | case SND_SOC_DAIFMT_CBM_CFM: |
98 | break; | 120 | break; |
121 | case SND_SOC_DAIFMT_CBS_CFS: | ||
122 | case SND_SOC_DAIFMT_CBM_CFS: | ||
99 | case SND_SOC_DAIFMT_CBS_CFM: | 123 | case SND_SOC_DAIFMT_CBS_CFM: |
100 | ret = -EINVAL; | 124 | ret = -EINVAL; |
101 | break; | 125 | break; |
102 | default: | 126 | default: |
127 | printk(KERN_ERR "%s: Unknown DAI master type\n", __func__); | ||
103 | ret = -EINVAL; | 128 | ret = -EINVAL; |
104 | break; | 129 | break; |
105 | } | 130 | } |
@@ -127,14 +152,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
127 | case SNDRV_PCM_FORMAT_S16_LE: | 152 | case SNDRV_PCM_FORMAT_S16_LE: |
128 | bf5xx_i2s.tcr2 |= 15; | 153 | bf5xx_i2s.tcr2 |= 15; |
129 | bf5xx_i2s.rcr2 |= 15; | 154 | bf5xx_i2s.rcr2 |= 15; |
155 | sport_handle->wdsize = 2; | ||
130 | break; | 156 | break; |
131 | case SNDRV_PCM_FORMAT_S24_LE: | 157 | case SNDRV_PCM_FORMAT_S24_LE: |
132 | bf5xx_i2s.tcr2 |= 23; | 158 | bf5xx_i2s.tcr2 |= 23; |
133 | bf5xx_i2s.rcr2 |= 23; | 159 | bf5xx_i2s.rcr2 |= 23; |
160 | sport_handle->wdsize = 3; | ||
134 | break; | 161 | break; |
135 | case SNDRV_PCM_FORMAT_S32_LE: | 162 | case SNDRV_PCM_FORMAT_S32_LE: |
136 | bf5xx_i2s.tcr2 |= 31; | 163 | bf5xx_i2s.tcr2 |= 31; |
137 | bf5xx_i2s.rcr2 |= 31; | 164 | bf5xx_i2s.rcr2 |= 31; |
165 | sport_handle->wdsize = 4; | ||
138 | break; | 166 | break; |
139 | } | 167 | } |
140 | 168 | ||
@@ -145,17 +173,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
145 | * need to configure both of them at the time when the first | 173 | * need to configure both of them at the time when the first |
146 | * stream is opened. | 174 | * stream is opened. |
147 | * | 175 | * |
148 | * CPU DAI format:I2S, slave mode. | 176 | * CPU DAI:slave mode. |
149 | */ | 177 | */ |
150 | ret = sport_config_rx(sport_handle, RFSR | RCKFE, | 178 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, |
151 | RSFSE|bf5xx_i2s.rcr2, 0, 0); | 179 | bf5xx_i2s.rcr2, 0, 0); |
152 | if (ret) { | 180 | if (ret) { |
153 | pr_err("SPORT is busy!\n"); | 181 | pr_err("SPORT is busy!\n"); |
154 | return -EBUSY; | 182 | return -EBUSY; |
155 | } | 183 | } |
156 | 184 | ||
157 | ret = sport_config_tx(sport_handle, TFSR | TCKFE, | 185 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, |
158 | TSFSE|bf5xx_i2s.tcr2, 0, 0); | 186 | bf5xx_i2s.tcr2, 0, 0); |
159 | if (ret) { | 187 | if (ret) { |
160 | pr_err("SPORT is busy!\n"); | 188 | pr_err("SPORT is busy!\n"); |
161 | return -EBUSY; | 189 | return -EBUSY; |
@@ -174,13 +202,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) | |||
174 | static int bf5xx_i2s_probe(struct platform_device *pdev, | 202 | static int bf5xx_i2s_probe(struct platform_device *pdev, |
175 | struct snd_soc_dai *dai) | 203 | struct snd_soc_dai *dai) |
176 | { | 204 | { |
177 | u16 sport_req[][7] = { | ||
178 | { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
179 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}, | ||
180 | { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, | ||
181 | P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}, | ||
182 | }; | ||
183 | |||
184 | pr_debug("%s enter\n", __func__); | 205 | pr_debug("%s enter\n", __func__); |
185 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | 206 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { |
186 | pr_err("Requesting Peripherals failed\n"); | 207 | pr_err("Requesting Peripherals failed\n"); |
@@ -198,6 +219,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, | |||
198 | return 0; | 219 | return 0; |
199 | } | 220 | } |
200 | 221 | ||
222 | static void bf5xx_i2s_remove(struct platform_device *pdev, | ||
223 | struct snd_soc_dai *dai) | ||
224 | { | ||
225 | pr_debug("%s enter\n", __func__); | ||
226 | peripheral_free_list(&sport_req[sport_num][0]); | ||
227 | } | ||
228 | |||
201 | #ifdef CONFIG_PM | 229 | #ifdef CONFIG_PM |
202 | static int bf5xx_i2s_suspend(struct platform_device *dev, | 230 | static int bf5xx_i2s_suspend(struct platform_device *dev, |
203 | struct snd_soc_dai *dai) | 231 | struct snd_soc_dai *dai) |
@@ -263,15 +291,16 @@ struct snd_soc_dai bf5xx_i2s_dai = { | |||
263 | .id = 0, | 291 | .id = 0, |
264 | .type = SND_SOC_DAI_I2S, | 292 | .type = SND_SOC_DAI_I2S, |
265 | .probe = bf5xx_i2s_probe, | 293 | .probe = bf5xx_i2s_probe, |
294 | .remove = bf5xx_i2s_remove, | ||
266 | .suspend = bf5xx_i2s_suspend, | 295 | .suspend = bf5xx_i2s_suspend, |
267 | .resume = bf5xx_i2s_resume, | 296 | .resume = bf5xx_i2s_resume, |
268 | .playback = { | 297 | .playback = { |
269 | .channels_min = 2, | 298 | .channels_min = 1, |
270 | .channels_max = 2, | 299 | .channels_max = 2, |
271 | .rates = BF5XX_I2S_RATES, | 300 | .rates = BF5XX_I2S_RATES, |
272 | .formats = BF5XX_I2S_FORMATS,}, | 301 | .formats = BF5XX_I2S_FORMATS,}, |
273 | .capture = { | 302 | .capture = { |
274 | .channels_min = 2, | 303 | .channels_min = 1, |
275 | .channels_max = 2, | 304 | .channels_max = 2, |
276 | .rates = BF5XX_I2S_RATES, | 305 | .rates = BF5XX_I2S_RATES, |
277 | .formats = BF5XX_I2S_FORMATS,}, | 306 | .formats = BF5XX_I2S_FORMATS,}, |