| OLD | NEW |
| 1 /* | 1 /* |
| 2 * smdk64xx_wm8580.c | 2 * smdk_wm8580.c |
| 3 * | 3 * |
| 4 * Copyright (c) 2009 Samsung Electronics Co. Ltd | 4 * Copyright (c) 2009 Samsung Electronics Co. Ltd |
| 5 * Author: Jaswinder Singh <jassi.brar@samsung.com> | 5 * Author: Jaswinder Singh <jassi.brar@samsung.com> |
| 6 * | 6 * |
| 7 * This program is free software; you can redistribute it and/or modify it | 7 * This program is free software; you can redistribute it and/or modify it |
| 8 * under the terms of the GNU General Public License as published by the | 8 * under the terms of the GNU General Public License as published by the |
| 9 * Free Software Foundation; either version 2 of the License, or (at your | 9 * Free Software Foundation; either version 2 of the License, or (at your |
| 10 * option) any later version. | 10 * option) any later version. |
| 11 */ | 11 */ |
| 12 | 12 |
| 13 #include <linux/platform_device.h> | 13 #include <sound/soc.h> |
| 14 #include <linux/clk.h> | |
| 15 #include <sound/core.h> | |
| 16 #include <sound/pcm.h> | |
| 17 #include <sound/pcm_params.h> | 14 #include <sound/pcm_params.h> |
| 18 #include <sound/soc.h> | 15 |
| 19 #include <sound/soc-dapm.h> | 16 #include <asm/mach-types.h> |
| 20 | 17 |
| 21 #include "../codecs/wm8580.h" | 18 #include "../codecs/wm8580.h" |
| 22 #include "s3c-dma.h" | 19 #include "i2s.h" |
| 23 #include "s3c64xx-i2s.h" | |
| 24 | 20 |
| 25 /* | 21 /* |
| 26 * Default CFG switch settings to use this driver: | 22 * Default CFG switch settings to use this driver: |
| 27 * | 23 * |
| 28 * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On | 24 * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On |
| 29 */ | 25 */ |
| 30 | 26 |
| 31 /* SMDK64XX has a 12MHZ crystal attached to WM8580 */ | 27 /* SMDK has a 12MHZ crystal attached to WM8580 */ |
| 32 #define SMDK64XX_WM8580_FREQ 12000000 | 28 #define SMDK_WM8580_FREQ 12000000 |
| 33 | 29 |
| 34 static int smdk64xx_hw_params(struct snd_pcm_substream *substream, | 30 static int smdk_hw_params(struct snd_pcm_substream *substream, |
| 35 struct snd_pcm_hw_params *params) | 31 struct snd_pcm_hw_params *params) |
| 36 { | 32 { |
| 37 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 33 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 38 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 34 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 39 struct snd_soc_dai *codec_dai = rtd->codec_dai; | 35 struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 40 unsigned int pll_out; | 36 unsigned int pll_out; |
| 41 int bfs, rfs, ret; | 37 int bfs, rfs, ret; |
| 42 | 38 |
| 43 switch (params_format(params)) { | 39 switch (params_format(params)) { |
| 44 case SNDRV_PCM_FORMAT_U8: | 40 case SNDRV_PCM_FORMAT_U8: |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 if (ret < 0) | 85 if (ret < 0) |
| 90 return ret; | 86 return ret; |
| 91 | 87 |
| 92 /* Set the AP DAI configuration */ | 88 /* Set the AP DAI configuration */ |
| 93 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 89 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
| 94 | SND_SOC_DAIFMT_NB_NF | 90 | SND_SOC_DAIFMT_NB_NF |
| 95 | SND_SOC_DAIFMT_CBM_CFM); | 91 | SND_SOC_DAIFMT_CBM_CFM); |
| 96 if (ret < 0) | 92 if (ret < 0) |
| 97 return ret; | 93 return ret; |
| 98 | 94 |
| 99 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK, | |
| 100 0, SND_SOC_CLOCK_IN); | |
| 101 if (ret < 0) | |
| 102 return ret; | |
| 103 | |
| 104 /* We use PCLK for basic ops in SoC-Slave mode */ | |
| 105 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK, | |
| 106 0, SND_SOC_CLOCK_IN); | |
| 107 if (ret < 0) | |
| 108 return ret; | |
| 109 | |
| 110 /* Set WM8580 to drive MCLK from its PLLA */ | 95 /* Set WM8580 to drive MCLK from its PLLA */ |
| 111 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, | 96 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, |
| 112 WM8580_CLKSRC_PLLA); | 97 WM8580_CLKSRC_PLLA); |
| 113 if (ret < 0) | 98 if (ret < 0) |
| 114 return ret; | 99 return ret; |
| 115 | 100 |
| 116 ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, | 101 ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, |
| 117 » » » » » SMDK64XX_WM8580_FREQ, pll_out); | 102 » » » » » SMDK_WM8580_FREQ, pll_out); |
| 118 if (ret < 0) | 103 if (ret < 0) |
| 119 return ret; | 104 return ret; |
| 120 | 105 |
| 121 ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, | 106 ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, |
| 122 pll_out, SND_SOC_CLOCK_IN); | 107 pll_out, SND_SOC_CLOCK_IN); |
| 123 if (ret < 0) | 108 if (ret < 0) |
| 124 return ret; | 109 return ret; |
| 125 | 110 |
| 126 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs); | |
| 127 if (ret < 0) | |
| 128 return ret; | |
| 129 | |
| 130 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs); | |
| 131 if (ret < 0) | |
| 132 return ret; | |
| 133 | |
| 134 return 0; | 111 return 0; |
| 135 } | 112 } |
| 136 | 113 |
| 137 /* | 114 /* |
| 138 * SMDK64XX WM8580 DAI operations. | 115 * SMDK WM8580 DAI operations. |
| 139 */ | 116 */ |
| 140 static struct snd_soc_ops smdk64xx_ops = { | 117 static struct snd_soc_ops smdk_ops = { |
| 141 » .hw_params = smdk64xx_hw_params, | 118 » .hw_params = smdk_hw_params, |
| 142 }; | 119 }; |
| 143 | 120 |
| 144 /* SMDK64xx Playback widgets */ | 121 /* SMDK Playback widgets */ |
| 145 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { | 122 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { |
| 146 SND_SOC_DAPM_HP("Front", NULL), | 123 SND_SOC_DAPM_HP("Front", NULL), |
| 147 SND_SOC_DAPM_HP("Center+Sub", NULL), | 124 SND_SOC_DAPM_HP("Center+Sub", NULL), |
| 148 SND_SOC_DAPM_HP("Rear", NULL), | 125 SND_SOC_DAPM_HP("Rear", NULL), |
| 149 }; | 126 }; |
| 150 | 127 |
| 151 /* SMDK64xx Capture widgets */ | 128 /* SMDK Capture widgets */ |
| 152 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { | 129 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { |
| 153 SND_SOC_DAPM_MIC("MicIn", NULL), | 130 SND_SOC_DAPM_MIC("MicIn", NULL), |
| 154 SND_SOC_DAPM_LINE("LineIn", NULL), | 131 SND_SOC_DAPM_LINE("LineIn", NULL), |
| 155 }; | 132 }; |
| 156 | 133 |
| 157 /* SMDK-PAIFTX connections */ | 134 /* SMDK-PAIFTX connections */ |
| 158 static const struct snd_soc_dapm_route audio_map_tx[] = { | 135 static const struct snd_soc_dapm_route audio_map_tx[] = { |
| 159 /* MicIn feeds AINL */ | 136 /* MicIn feeds AINL */ |
| 160 {"AINL", NULL, "MicIn"}, | 137 {"AINL", NULL, "MicIn"}, |
| 161 | 138 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 172 | 149 |
| 173 /* Center/Sub are fed VOUT2L/R */ | 150 /* Center/Sub are fed VOUT2L/R */ |
| 174 {"Center+Sub", NULL, "VOUT2L"}, | 151 {"Center+Sub", NULL, "VOUT2L"}, |
| 175 {"Center+Sub", NULL, "VOUT2R"}, | 152 {"Center+Sub", NULL, "VOUT2R"}, |
| 176 | 153 |
| 177 /* Rear Left/Right are fed VOUT3L/R */ | 154 /* Rear Left/Right are fed VOUT3L/R */ |
| 178 {"Rear", NULL, "VOUT3L"}, | 155 {"Rear", NULL, "VOUT3L"}, |
| 179 {"Rear", NULL, "VOUT3R"}, | 156 {"Rear", NULL, "VOUT3R"}, |
| 180 }; | 157 }; |
| 181 | 158 |
| 182 static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) | 159 static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) |
| 183 { | 160 { |
| 184 struct snd_soc_codec *codec = rtd->codec; | 161 struct snd_soc_codec *codec = rtd->codec; |
| 162 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 185 | 163 |
| 186 » /* Add smdk64xx specific Capture widgets */ | 164 » /* Add smdk specific Capture widgets */ |
| 187 » snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt, | 165 » snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_cpt, |
| 188 ARRAY_SIZE(wm8580_dapm_widgets_cpt)); | 166 ARRAY_SIZE(wm8580_dapm_widgets_cpt)); |
| 189 | 167 |
| 190 /* Set up PAIFTX audio path */ | 168 /* Set up PAIFTX audio path */ |
| 191 » snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); | 169 » snd_soc_dapm_add_routes(dapm, audio_map_tx, ARRAY_SIZE(audio_map_tx)); |
| 192 | 170 |
| 193 /* Enabling the microphone requires the fitting of a 0R | 171 /* Enabling the microphone requires the fitting of a 0R |
| 194 * resistor to connect the line from the microphone jack. | 172 * resistor to connect the line from the microphone jack. |
| 195 */ | 173 */ |
| 196 » snd_soc_dapm_disable_pin(codec, "MicIn"); | 174 » snd_soc_dapm_disable_pin(dapm, "MicIn"); |
| 197 | 175 |
| 198 /* signal a DAPM event */ | 176 /* signal a DAPM event */ |
| 199 » snd_soc_dapm_sync(codec); | 177 » snd_soc_dapm_sync(dapm); |
| 200 | 178 |
| 201 return 0; | 179 return 0; |
| 202 } | 180 } |
| 203 | 181 |
| 204 static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd) | 182 static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd) |
| 205 { | 183 { |
| 206 struct snd_soc_codec *codec = rtd->codec; | 184 struct snd_soc_codec *codec = rtd->codec; |
| 185 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 207 | 186 |
| 208 » /* Add smdk64xx specific Playback widgets */ | 187 » /* Add smdk specific Playback widgets */ |
| 209 » snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk, | 188 » snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_pbk, |
| 210 ARRAY_SIZE(wm8580_dapm_widgets_pbk)); | 189 ARRAY_SIZE(wm8580_dapm_widgets_pbk)); |
| 211 | 190 |
| 212 /* Set up PAIFRX audio path */ | 191 /* Set up PAIFRX audio path */ |
| 213 » snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); | 192 » snd_soc_dapm_add_routes(dapm, audio_map_rx, ARRAY_SIZE(audio_map_rx)); |
| 214 | 193 |
| 215 /* signal a DAPM event */ | 194 /* signal a DAPM event */ |
| 216 » snd_soc_dapm_sync(codec); | 195 » snd_soc_dapm_sync(dapm); |
| 217 | 196 |
| 218 return 0; | 197 return 0; |
| 219 } | 198 } |
| 220 | 199 |
| 221 static struct snd_soc_dai_link smdk64xx_dai[] = { | 200 enum { |
| 222 { /* Primary Playback i/f */ | 201 » PRI_PLAYBACK = 0, |
| 223 » .name = "WM8580 PAIF RX", | 202 » PRI_CAPTURE, |
| 224 » .stream_name = "Playback", | 203 » SEC_PLAYBACK, |
| 225 » .cpu_dai_name = "s3c64xx-iis-v4", | |
| 226 » .codec_dai_name = "wm8580-hifi-playback", | |
| 227 » .platform_name = "s3c24xx-pcm-audio", | |
| 228 » .codec_name = "wm8580-codec.0-001b", | |
| 229 » .init = smdk64xx_wm8580_init_paifrx, | |
| 230 » .ops = &smdk64xx_ops, | |
| 231 }, | |
| 232 { /* Primary Capture i/f */ | |
| 233 » .name = "WM8580 PAIF TX", | |
| 234 » .stream_name = "Capture", | |
| 235 » .cpu_dai_name = "s3c64xx-iis-v4", | |
| 236 » .codec_dai_name = "wm8580-hifi-capture", | |
| 237 » .platform_name = "s3c24xx-pcm-audio", | |
| 238 » .codec_name = "wm8580-codec.0-001b", | |
| 239 » .init = smdk64xx_wm8580_init_paiftx, | |
| 240 » .ops = &smdk64xx_ops, | |
| 241 }, | |
| 242 }; | 204 }; |
| 243 | 205 |
| 244 static struct snd_soc_card smdk64xx = { | 206 static struct snd_soc_dai_link smdk_dai[] = { |
| 245 » .name = "SMDK64xx 5.1", | 207 » [PRI_PLAYBACK] = { /* Primary Playback i/f */ |
| 246 » .dai_link = smdk64xx_dai, | 208 » » .name = "WM8580 PAIF RX", |
| 247 » .num_links = ARRAY_SIZE(smdk64xx_dai), | 209 » » .stream_name = "Playback", |
| 210 » » .cpu_dai_name = "samsung-i2s.0", |
| 211 » » .codec_dai_name = "wm8580-hifi-playback", |
| 212 » » .platform_name = "samsung-audio", |
| 213 » » .codec_name = "wm8580-codec.0-001b", |
| 214 » » .init = smdk_wm8580_init_paifrx, |
| 215 » » .ops = &smdk_ops, |
| 216 » }, |
| 217 » [PRI_CAPTURE] = { /* Primary Capture i/f */ |
| 218 » » .name = "WM8580 PAIF TX", |
| 219 » » .stream_name = "Capture", |
| 220 » » .cpu_dai_name = "samsung-i2s.0", |
| 221 » » .codec_dai_name = "wm8580-hifi-capture", |
| 222 » » .platform_name = "samsung-audio", |
| 223 » » .codec_name = "wm8580-codec.0-001b", |
| 224 » » .init = smdk_wm8580_init_paiftx, |
| 225 » » .ops = &smdk_ops, |
| 226 » }, |
| 227 » [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ |
| 228 » » .name = "Sec_FIFO TX", |
| 229 » » .stream_name = "Playback", |
| 230 » » .cpu_dai_name = "samsung-i2s.x", |
| 231 » » .codec_dai_name = "wm8580-hifi-playback", |
| 232 » » .platform_name = "samsung-audio", |
| 233 » » .codec_name = "wm8580-codec.0-001b", |
| 234 » » .init = smdk_wm8580_init_paifrx, |
| 235 » » .ops = &smdk_ops, |
| 236 » }, |
| 248 }; | 237 }; |
| 249 | 238 |
| 250 static struct platform_device *smdk64xx_snd_device; | 239 static struct snd_soc_card smdk = { |
| 240 » .name = "SMDK-I2S", |
| 241 » .dai_link = smdk_dai, |
| 242 » .num_links = 2, |
| 243 }; |
| 251 | 244 |
| 252 static int __init smdk64xx_audio_init(void) | 245 static struct platform_device *smdk_snd_device; |
| 246 |
| 247 static int __init smdk_audio_init(void) |
| 253 { | 248 { |
| 254 int ret; | 249 int ret; |
| 250 char *str; |
| 255 | 251 |
| 256 » smdk64xx_snd_device = platform_device_alloc("soc-audio", -1); | 252 » if (machine_is_smdkc100() || machine_is_smdk6442() |
| 257 » if (!smdk64xx_snd_device) | 253 » » » || machine_is_smdkv210() || machine_is_smdkc110()) { |
| 254 » » smdk.num_links = 3; |
| 255 » » /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ |
| 256 » » str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; |
| 257 » » str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; |
| 258 » } else if (machine_is_smdk6410()) { |
| 259 » » str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; |
| 260 » » str[strlen(str) - 1] = '2'; |
| 261 » » str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; |
| 262 » » str[strlen(str) - 1] = '2'; |
| 263 » } |
| 264 |
| 265 » smdk_snd_device = platform_device_alloc("soc-audio", -1); |
| 266 » if (!smdk_snd_device) |
| 258 return -ENOMEM; | 267 return -ENOMEM; |
| 259 | 268 |
| 260 » platform_set_drvdata(smdk64xx_snd_device, &smdk64xx); | 269 » platform_set_drvdata(smdk_snd_device, &smdk); |
| 261 » ret = platform_device_add(smdk64xx_snd_device); | 270 » ret = platform_device_add(smdk_snd_device); |
| 262 | 271 |
| 263 if (ret) | 272 if (ret) |
| 264 » » platform_device_put(smdk64xx_snd_device); | 273 » » platform_device_put(smdk_snd_device); |
| 265 | 274 |
| 266 return ret; | 275 return ret; |
| 267 } | 276 } |
| 268 module_init(smdk64xx_audio_init); | 277 module_init(smdk_audio_init); |
| 278 |
| 279 static void __exit smdk_audio_exit(void) |
| 280 { |
| 281 » platform_device_unregister(smdk_snd_device); |
| 282 } |
| 283 module_exit(smdk_audio_exit); |
| 269 | 284 |
| 270 MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); | 285 MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); |
| 271 MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580"); | 286 MODULE_DESCRIPTION("ALSA SoC SMDK WM8580"); |
| 272 MODULE_LICENSE("GPL"); | 287 MODULE_LICENSE("GPL"); |
| OLD | NEW |