| OLD | NEW |
| 1 /* sound/soc/s3c24xx/smartq_wm8987.c | 1 /* sound/soc/samsung/smartq_wm8987.c |
| 2 * | 2 * |
| 3 * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> | 3 * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> |
| 4 * | 4 * |
| 5 * Based on smdk6410_wm8987.c | 5 * Based on smdk6410_wm8987.c |
| 6 * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com | 6 * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com |
| 7 * Graeme Gregory - graeme.gregory@wolfsonmicro.com | 7 * Graeme Gregory - graeme.gregory@wolfsonmicro.com |
| 8 * | 8 * |
| 9 * This program is free software; you can redistribute it and/or modify it | 9 * This program is free software; you can redistribute it and/or modify it |
| 10 * under the terms of the GNU General Public License as published by the | 10 * under the terms of the GNU General Public License as published by the |
| 11 * Free Software Foundation; either version 2 of the License, or (at your | 11 * Free Software Foundation; either version 2 of the License, or (at your |
| 12 * option) any later version. | 12 * option) any later version. |
| 13 * | 13 * |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include <linux/module.h> | |
| 17 #include <linux/platform_device.h> | |
| 18 #include <linux/gpio.h> | 16 #include <linux/gpio.h> |
| 19 | 17 |
| 20 #include <sound/pcm.h> | 18 #include <sound/soc.h> |
| 21 #include <sound/pcm_params.h> | |
| 22 #include <sound/soc-dapm.h> | |
| 23 #include <sound/jack.h> | 19 #include <sound/jack.h> |
| 24 | 20 |
| 25 #include <asm/mach-types.h> | 21 #include <asm/mach-types.h> |
| 26 | 22 |
| 27 #include "s3c-dma.h" | 23 #include "i2s.h" |
| 28 #include "s3c64xx-i2s.h" | |
| 29 | |
| 30 #include "../codecs/wm8750.h" | 24 #include "../codecs/wm8750.h" |
| 31 | 25 |
| 32 /* | 26 /* |
| 33 * WM8987 is register compatible with WM8750, so using that as base driver. | 27 * WM8987 is register compatible with WM8750, so using that as base driver. |
| 34 */ | 28 */ |
| 35 | 29 |
| 36 static struct snd_soc_card snd_soc_smartq; | 30 static struct snd_soc_card snd_soc_smartq; |
| 37 | 31 |
| 38 static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, | 32 static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, |
| 39 struct snd_pcm_hw_params *params) | 33 struct snd_pcm_hw_params *params) |
| 40 { | 34 { |
| 41 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 35 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 42 » struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 36 » struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 43 » struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 37 » struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 44 » struct s3c_i2sv2_rate_calc div; | |
| 45 unsigned int clk = 0; | 38 unsigned int clk = 0; |
| 46 int ret; | 39 int ret; |
| 47 | 40 |
| 48 s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), | |
| 49 s3c_i2sv2_get_clock(cpu_dai)); | |
| 50 | |
| 51 switch (params_rate(params)) { | 41 switch (params_rate(params)) { |
| 52 case 8000: | 42 case 8000: |
| 53 case 16000: | 43 case 16000: |
| 54 case 32000: | 44 case 32000: |
| 55 case 48000: | 45 case 48000: |
| 56 case 96000: | 46 case 96000: |
| 57 clk = 12288000; | 47 clk = 12288000; |
| 58 break; | 48 break; |
| 59 case 11025: | 49 case 11025: |
| 60 case 22050: | 50 case 22050: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 71 if (ret < 0) | 61 if (ret < 0) |
| 72 return ret; | 62 return ret; |
| 73 | 63 |
| 74 /* set cpu DAI configuration */ | 64 /* set cpu DAI configuration */ |
| 75 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 65 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 76 SND_SOC_DAIFMT_NB_NF | | 66 SND_SOC_DAIFMT_NB_NF | |
| 77 SND_SOC_DAIFMT_CBS_CFS); | 67 SND_SOC_DAIFMT_CBS_CFS); |
| 78 if (ret < 0) | 68 if (ret < 0) |
| 79 return ret; | 69 return ret; |
| 80 | 70 |
| 71 /* Use PCLK for I2S signal generation */ |
| 72 ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, |
| 73 0, SND_SOC_CLOCK_IN); |
| 74 if (ret < 0) |
| 75 return ret; |
| 76 |
| 77 /* Gate the RCLK output on PAD */ |
| 78 ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, |
| 79 0, SND_SOC_CLOCK_IN); |
| 80 if (ret < 0) |
| 81 return ret; |
| 82 |
| 81 /* set the codec system clock for DAC and ADC */ | 83 /* set the codec system clock for DAC and ADC */ |
| 82 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 84 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
| 83 SND_SOC_CLOCK_IN); | 85 SND_SOC_CLOCK_IN); |
| 84 if (ret < 0) | 86 if (ret < 0) |
| 85 return ret; | 87 return ret; |
| 86 | 88 |
| 87 /* set MCLK division for sample rate */ | |
| 88 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div); | |
| 89 if (ret < 0) | |
| 90 return ret; | |
| 91 | |
| 92 /* set prescaler division for sample rate */ | |
| 93 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER, | |
| 94 div.clk_div - 1); | |
| 95 if (ret < 0) | |
| 96 return ret; | |
| 97 | |
| 98 return 0; | 89 return 0; |
| 99 } | 90 } |
| 100 | 91 |
| 101 /* | 92 /* |
| 102 * SmartQ WM8987 HiFi DAI operations. | 93 * SmartQ WM8987 HiFi DAI operations. |
| 103 */ | 94 */ |
| 104 static struct snd_soc_ops smartq_hifi_ops = { | 95 static struct snd_soc_ops smartq_hifi_ops = { |
| 105 .hw_params = smartq_hifi_hw_params, | 96 .hw_params = smartq_hifi_hw_params, |
| 106 }; | 97 }; |
| 107 | 98 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 {"Headphone Jack", NULL, "LOUT2"}, | 140 {"Headphone Jack", NULL, "LOUT2"}, |
| 150 {"Headphone Jack", NULL, "ROUT2"}, | 141 {"Headphone Jack", NULL, "ROUT2"}, |
| 151 | 142 |
| 152 {"Internal Speaker", NULL, "LOUT2"}, | 143 {"Internal Speaker", NULL, "LOUT2"}, |
| 153 {"Internal Speaker", NULL, "ROUT2"}, | 144 {"Internal Speaker", NULL, "ROUT2"}, |
| 154 | 145 |
| 155 {"Mic Bias", NULL, "Internal Mic"}, | 146 {"Mic Bias", NULL, "Internal Mic"}, |
| 156 {"LINPUT2", NULL, "Mic Bias"}, | 147 {"LINPUT2", NULL, "Mic Bias"}, |
| 157 }; | 148 }; |
| 158 | 149 |
| 159 static int smartq_wm8987_init(struct snd_soc_codec *codec) | 150 static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) |
| 160 { | 151 { |
| 152 struct snd_soc_codec *codec = rtd->codec; |
| 153 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 161 int err = 0; | 154 int err = 0; |
| 162 | 155 |
| 163 /* Add SmartQ specific widgets */ | 156 /* Add SmartQ specific widgets */ |
| 164 » snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets, | 157 » snd_soc_dapm_new_controls(dapm, wm8987_dapm_widgets, |
| 165 ARRAY_SIZE(wm8987_dapm_widgets)); | 158 ARRAY_SIZE(wm8987_dapm_widgets)); |
| 166 | 159 |
| 167 /* add SmartQ specific controls */ | 160 /* add SmartQ specific controls */ |
| 168 err = snd_soc_add_controls(codec, wm8987_smartq_controls, | 161 err = snd_soc_add_controls(codec, wm8987_smartq_controls, |
| 169 ARRAY_SIZE(wm8987_smartq_controls)); | 162 ARRAY_SIZE(wm8987_smartq_controls)); |
| 170 | 163 |
| 171 if (err < 0) | 164 if (err < 0) |
| 172 return err; | 165 return err; |
| 173 | 166 |
| 174 /* setup SmartQ specific audio path */ | 167 /* setup SmartQ specific audio path */ |
| 175 » snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 168 » snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
| 176 | 169 |
| 177 /* set endpoints to not connected */ | 170 /* set endpoints to not connected */ |
| 178 » snd_soc_dapm_nc_pin(codec, "LINPUT1"); | 171 » snd_soc_dapm_nc_pin(dapm, "LINPUT1"); |
| 179 » snd_soc_dapm_nc_pin(codec, "RINPUT1"); | 172 » snd_soc_dapm_nc_pin(dapm, "RINPUT1"); |
| 180 » snd_soc_dapm_nc_pin(codec, "OUT3"); | 173 » snd_soc_dapm_nc_pin(dapm, "OUT3"); |
| 181 » snd_soc_dapm_nc_pin(codec, "ROUT1"); | 174 » snd_soc_dapm_nc_pin(dapm, "ROUT1"); |
| 182 | 175 |
| 183 /* set endpoints to default off mode */ | 176 /* set endpoints to default off mode */ |
| 184 » snd_soc_dapm_enable_pin(codec, "Internal Speaker"); | 177 » snd_soc_dapm_enable_pin(dapm, "Internal Speaker"); |
| 185 » snd_soc_dapm_enable_pin(codec, "Internal Mic"); | 178 » snd_soc_dapm_enable_pin(dapm, "Internal Mic"); |
| 186 » snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | 179 » snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
| 187 | 180 |
| 188 » err = snd_soc_dapm_sync(codec); | 181 » err = snd_soc_dapm_sync(dapm); |
| 189 if (err) | 182 if (err) |
| 190 return err; | 183 return err; |
| 191 | 184 |
| 192 /* Headphone jack detection */ | 185 /* Headphone jack detection */ |
| 193 » err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack", | 186 » err = snd_soc_jack_new(codec, "Headphone Jack", |
| 194 SND_JACK_HEADPHONE, &smartq_jack); | 187 SND_JACK_HEADPHONE, &smartq_jack); |
| 195 if (err) | 188 if (err) |
| 196 return err; | 189 return err; |
| 197 | 190 |
| 198 err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), | 191 err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), |
| 199 smartq_jack_pins); | 192 smartq_jack_pins); |
| 200 if (err) | 193 if (err) |
| 201 return err; | 194 return err; |
| 202 | 195 |
| 203 err = snd_soc_jack_add_gpios(&smartq_jack, | 196 err = snd_soc_jack_add_gpios(&smartq_jack, |
| 204 ARRAY_SIZE(smartq_jack_gpios), | 197 ARRAY_SIZE(smartq_jack_gpios), |
| 205 smartq_jack_gpios); | 198 smartq_jack_gpios); |
| 206 | 199 |
| 207 return err; | 200 return err; |
| 208 } | 201 } |
| 209 | 202 |
| 210 static struct snd_soc_dai_link smartq_dai[] = { | 203 static struct snd_soc_dai_link smartq_dai[] = { |
| 211 { | 204 { |
| 212 .name = "wm8987", | 205 .name = "wm8987", |
| 213 .stream_name = "SmartQ Hi-Fi", | 206 .stream_name = "SmartQ Hi-Fi", |
| 214 » » .cpu_dai_name» = "s3c64xx-i2s.0", | 207 » » .cpu_dai_name» = "samsung-i2s.0", |
| 215 .codec_dai_name = "wm8750-hifi", | 208 .codec_dai_name = "wm8750-hifi", |
| 216 » » .platform_name» = "s3c24xx-pcm-audio", | 209 » » .platform_name» = "samsung-audio", |
| 217 .codec_name = "wm8750-codec.0-0x1a", | 210 .codec_name = "wm8750-codec.0-0x1a", |
| 218 .init = smartq_wm8987_init, | 211 .init = smartq_wm8987_init, |
| 219 .ops = &smartq_hifi_ops, | 212 .ops = &smartq_hifi_ops, |
| 220 }, | 213 }, |
| 221 }; | 214 }; |
| 222 | 215 |
| 223 static struct snd_soc_card snd_soc_smartq = { | 216 static struct snd_soc_card snd_soc_smartq = { |
| 224 .name = "SmartQ", | 217 .name = "SmartQ", |
| 225 .dai_link = smartq_dai, | 218 .dai_link = smartq_dai, |
| 226 .num_links = ARRAY_SIZE(smartq_dai), | 219 .num_links = ARRAY_SIZE(smartq_dai), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 err_free_gpio_amp_shut: | 261 err_free_gpio_amp_shut: |
| 269 gpio_free(S3C64XX_GPK(12)); | 262 gpio_free(S3C64XX_GPK(12)); |
| 270 err_unregister_device: | 263 err_unregister_device: |
| 271 platform_device_unregister(smartq_snd_device); | 264 platform_device_unregister(smartq_snd_device); |
| 272 | 265 |
| 273 return ret; | 266 return ret; |
| 274 } | 267 } |
| 275 | 268 |
| 276 static void __exit smartq_exit(void) | 269 static void __exit smartq_exit(void) |
| 277 { | 270 { |
| 271 gpio_free(S3C64XX_GPK(12)); |
| 278 snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), | 272 snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), |
| 279 smartq_jack_gpios); | 273 smartq_jack_gpios); |
| 280 | 274 |
| 281 platform_device_unregister(smartq_snd_device); | 275 platform_device_unregister(smartq_snd_device); |
| 282 } | 276 } |
| 283 | 277 |
| 284 module_init(smartq_init); | 278 module_init(smartq_init); |
| 285 module_exit(smartq_exit); | 279 module_exit(smartq_exit); |
| 286 | 280 |
| 287 /* Module information */ | 281 /* Module information */ |
| 288 MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>"); | 282 MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>"); |
| 289 MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987"); | 283 MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987"); |
| 290 MODULE_LICENSE("GPL"); | 284 MODULE_LICENSE("GPL"); |
| OLD | NEW |