diff options
Diffstat (limited to 'sound/soc/samsung')
34 files changed, 739 insertions, 641 deletions
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 9855dfc3e3e..753b8c93ab5 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,16 +1,25 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" depends on PLAT_SAMSUNG - select S3C64XX_DMA if ARCH_S3C64XX select S3C2410_DMA if ARCH_S3C24XX + select S3C64XX_PL080 if ARCH_S3C64XX + select SND_S3C_DMA if !ARCH_S3C24XX + select SND_S3C_DMA_LEGACY if ARCH_S3C24XX + select SND_SOC_GENERIC_DMAENGINE_PCM if !ARCH_S3C24XX help Say Y or M if you want to add support for codecs attached to the Samsung SoCs' Audio interfaces. You will also need to select the audio interfaces to support below. +config SND_S3C_DMA + tristate + +config SND_S3C_DMA_LEGACY + tristate + config SND_S3C24XX_I2S tristate - select S3C2410_DMA + select S3C24XX_DMA config SND_S3C_I2SV2_SOC tristate @@ -50,11 +59,12 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 select SND_SOC_WM8750 select SND_S3C2412_SOC_I2S help - Sat Y if you want to add support for SoC audio on the Jive. + Say Y if you want to add support for SoC audio on the Jive. config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) + depends on REGMAP_I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S help @@ -63,7 +73,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8994 tristate "SoC I2S Audio support for WM8994 on SMDK" depends on SND_SOC_SAMSUNG - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_I2S @@ -106,21 +116,21 @@ config SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX + depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C select SND_S3C24XX_I2S - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C select SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_SIMTEC_HERMES tristate "SoC I2S Audio support for Simtec Hermes board" - depends on SND_SOC_SAMSUNG && ARCH_S3C24XX + depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C select SND_S3C24XX_I2S select SND_SOC_TLV320AIC3X select SND_SOC_SAMSUNG_SIMTEC config SND_SOC_SAMSUNG_H1940_UDA1380 tristate "Audio support for the HP iPAQ H1940" - depends on SND_SOC_SAMSUNG && ARCH_H1940 + depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C select SND_S3C24XX_I2S select SND_SOC_UDA1380 help @@ -128,7 +138,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380 config SND_SOC_SAMSUNG_RX1950_UDA1380 tristate "Audio support for the HP iPAQ RX1950" - depends on SND_SOC_SAMSUNG && MACH_RX1950 + depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C select SND_S3C24XX_I2S select SND_SOC_UDA1380 help @@ -136,11 +146,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SAMSUNG_SMDK_WM9713 tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210) + depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) select SND_SOC_WM9713 select SND_SAMSUNG_AC97 help - Sat Y if you want to add support for SoC audio on the SMDK. + Say Y if you want to add support for SoC audio on the SMDK. config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" @@ -151,7 +161,7 @@ config SND_SOC_SMARTQ config SND_SOC_GONI_AQUILA_WM8994 tristate "SoC I2S Audio support for AQUILA/GONI - WM8994" depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA) - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select SND_SAMSUNG_I2S select MFD_WM8994 select SND_SOC_WM8994 @@ -169,6 +179,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF config SND_SOC_SMDK_WM8580_PCM tristate "SoC PCM Audio support for WM8580 on SMDK" depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110) + depends on REGMAP_I2C select SND_SOC_WM8580 select SND_SAMSUNG_PCM help @@ -177,7 +188,7 @@ config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" depends on SND_SOC_SAMSUNG - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_PCM @@ -195,13 +206,13 @@ config SND_SOC_SPEYSIDE config SND_SOC_TOBERMORY tristate "Audio support for Wolfson Tobermory" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT select SND_SAMSUNG_I2S select SND_SOC_WM8962 config SND_SOC_BELLS tristate "Audio support for Wolfson Bells" - depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 + depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA select SND_SAMSUNG_I2S select SND_SOC_WM5102 select SND_SOC_WM5110 @@ -222,3 +233,13 @@ config SND_SOC_LITTLEMILL select SND_SAMSUNG_I2S select MFD_WM8994 select SND_SOC_WM8994 + +config SND_SOC_SNOW + tristate "Audio support for Google Snow boards" + depends on SND_SOC_SAMSUNG + select SND_SOC_MAX98090 + select SND_SOC_MAX98095 + select SND_SAMSUNG_I2S + help + Say Y if you want to add audio support for various Snow + boards based on Exynos5 series of SoCs. diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 709f6059ad6..6d0212ba571 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -1,5 +1,6 @@ # S3c24XX Platform Support -snd-soc-s3c24xx-objs := dma.o +snd-soc-s3c-dma-objs := dmaengine.o +snd-soc-s3c-dma-legacy-objs := dma.o snd-soc-idma-objs := idma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o @@ -9,7 +10,8 @@ snd-soc-samsung-spdif-objs := spdif.o snd-soc-pcm-objs := pcm.o snd-soc-i2s-objs := i2s.o -obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o +obj-$(CONFIG_SND_S3C_DMA) += snd-soc-s3c-dma.o +obj-$(CONFIG_SND_S3C_DMA_LEGACY) += snd-soc-s3c-dma-legacy.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o @@ -32,6 +34,7 @@ snd-soc-h1940-uda1380-objs := h1940_uda1380.o snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o snd-soc-smdk-wm8580-objs := smdk_wm8580.o snd-soc-smdk-wm8994-objs := smdk_wm8994.o +snd-soc-snow-objs := snow.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-goni-wm8994-objs := goni_wm8994.o @@ -56,6 +59,7 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o +obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 2dd623fa388..68d9303047e 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -39,15 +39,15 @@ struct s3c_ac97_info { }; static struct s3c_ac97_info s3c_ac97; -static struct s3c2410_dma_client s3c_dma_client_out = { +static struct s3c_dma_client s3c_dma_client_out = { .name = "AC97 PCMOut" }; -static struct s3c2410_dma_client s3c_dma_client_in = { +static struct s3c_dma_client s3c_dma_client_in = { .name = "AC97 PCMIn" }; -static struct s3c2410_dma_client s3c_dma_client_micin = { +static struct s3c_dma_client s3c_dma_client_micin = { .name = "AC97 MicIn" }; @@ -74,7 +74,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97) if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) return; /* Return if already active */ - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; @@ -103,7 +103,7 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, s3c_ac97_activate(ac97); - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); @@ -140,7 +140,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, s3c_ac97_activate(ac97); - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); @@ -221,24 +221,6 @@ static struct snd_ac97_bus_ops s3c_ac97_ops = { .reset = s3c_ac97_cold_reset, }; -static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct s3c_dma_params *dma_data; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dma_data = &s3c_ac97_pcm_out; - else - dma_data = &s3c_ac97_pcm_in; - - snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); - - return 0; -} - static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -279,21 +261,6 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return -ENODEV; - else - snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in); - - return 0; -} - static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -329,15 +296,27 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops s3c_ac97_dai_ops = { - .hw_params = s3c_ac97_hw_params, .trigger = s3c_ac97_trigger, }; static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { - .hw_params = s3c_ac97_hw_mic_params, .trigger = s3c_ac97_mic_trigger, }; +static int s3c_ac97_dai_probe(struct snd_soc_dai *dai) +{ + samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); + + return 0; +} + +static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) +{ + samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in); + + return 0; +} + static struct snd_soc_dai_driver s3c_ac97_dai[] = { [S3C_AC97_DAI_PCM] = { .name = "samsung-ac97", @@ -354,6 +333,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .probe = s3c_ac97_dai_probe, .ops = &s3c_ac97_dai_ops, }, [S3C_AC97_DAI_MIC] = { @@ -365,6 +345,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { .channels_max = 1, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .probe = s3c_ac97_mic_dai_probe, .ops = &s3c_ac97_mic_dai_ops, }, }; @@ -404,18 +385,13 @@ static int s3c_ac97_probe(struct platform_device *pdev) return -ENXIO; } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem_res) { - dev_err(&pdev->dev, "Unable to get register resource\n"); - return -ENXIO; - } - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); return -ENXIO; } + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(s3c_ac97.regs)) return PTR_ERR(s3c_ac97.regs); @@ -457,20 +433,18 @@ static int s3c_ac97_probe(struct platform_device *pdev) goto err4; } - ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component, + ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component, s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); if (ret) goto err5; - ret = asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err6; + goto err5; } return 0; -err6: - snd_soc_unregister_component(&pdev->dev); err5: free_irq(irq_res->start, NULL); err4: @@ -485,9 +459,6 @@ static int s3c_ac97_remove(struct platform_device *pdev) { struct resource *irq_res; - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) free_irq(irq_res->start, NULL); diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 29e24680362..5b21207cf55 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -356,6 +356,7 @@ static struct snd_soc_dapm_widget bells_widgets[] = { static struct snd_soc_dapm_route bells_routes[] = { { "Sub CLK_SYS", NULL, "OPCLK" }, + { "CLKIN", NULL, "OPCLK" }, { "DMIC", NULL, "MICBIAS2" }, { "IN2L", NULL, "DMIC" }, @@ -432,22 +433,13 @@ static int bells_probe(struct platform_device *pdev) bells_cards[pdev->id].dev = &pdev->dev; - ret = snd_soc_register_card(&bells_cards[pdev->id]); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card(%s) failed: %d\n", bells_cards[pdev->id].name, ret); - return ret; - } - - return 0; -} - -static int bells_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&bells_cards[pdev->id]); - return 0; + return ret; } static struct platform_driver bells_driver = { @@ -457,7 +449,6 @@ static struct platform_driver bells_driver = { .pm = &snd_soc_pm_ops, }, .probe = bells_probe, - .remove = bells_remove, }; module_platform_driver(bells_driver); diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 21b79262010..d9dc7bcc033 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -35,12 +35,6 @@ static const struct snd_pcm_hardware dma_hardware = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8, - .channels_min = 2, - .channels_max = 2, .buffer_bytes_max = 128*1024, .period_bytes_min = PAGE_SIZE, .period_bytes_max = PAGE_SIZE*2, @@ -90,6 +84,13 @@ static void dma_enqueue(struct snd_pcm_substream *substream) dma_info.period = prtd->dma_period; dma_info.len = prtd->dma_period*limit; + if (dma_info.cap == DMA_CYCLIC) { + dma_info.buf = pos; + prtd->params->ops->prepare(prtd->params->ch, &dma_info); + prtd->dma_loaded += limit; + return; + } + while (prtd->dma_loaded < limit) { pr_debug("dma_loaded: %d\n", prtd->dma_loaded); @@ -176,6 +177,10 @@ static int dma_hw_params(struct snd_pcm_substream *substream, prtd->params->ch = prtd->params->ops->request( prtd->params->channel, &req, rtd->cpu_dai->dev, prtd->params->ch_name); + if (!prtd->params->ch) { + pr_err("Failed to allocate DMA channel\n"); + return -ENXIO; + } prtd->params->ops->config(prtd->params->ch, &config); } @@ -395,20 +400,17 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm) } } -static u64 dma_mask = DMA_BIT_MASK(32); - static int dma_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; - int ret = 0; + int ret; pr_debug("Entered %s\n", __func__); - if (!card->dev->dma_mask) - card->dev->dma_mask = &dma_mask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = preallocate_dma_buffer(pcm, @@ -433,17 +435,19 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { .pcm_free = dma_free_dma_buffers, }; -int asoc_dma_platform_register(struct device *dev) +void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, + struct s3c_dma_params *playback, + struct s3c_dma_params *capture) { - return snd_soc_register_platform(dev, &samsung_asoc_platform); + snd_soc_dai_init_dma_data(dai, playback, capture); } -EXPORT_SYMBOL_GPL(asoc_dma_platform_register); +EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); -void asoc_dma_platform_unregister(struct device *dev) +int samsung_asoc_dma_platform_register(struct device *dev) { - snd_soc_unregister_platform(dev); + return devm_snd_soc_register_platform(dev, &samsung_asoc_platform); } -EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister); +EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 189a7a6d502..070ab0f0960 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -12,17 +12,26 @@ #ifndef _S3C_AUDIO_H #define _S3C_AUDIO_H +#include <sound/dmaengine_pcm.h> + +struct s3c_dma_client { + char *name; +}; + struct s3c_dma_params { - struct s3c2410_dma_client *client; /* stream identifier */ + struct s3c_dma_client *client; /* stream identifier */ int channel; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ unsigned ch; struct samsung_dma_ops *ops; char *ch_name; + struct snd_dmaengine_dai_dma_data dma_data; }; -int asoc_dma_platform_register(struct device *dev); -void asoc_dma_platform_unregister(struct device *dev); +void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, + struct s3c_dma_params *playback, + struct s3c_dma_params *capture); +int samsung_asoc_dma_platform_register(struct device *dev); #endif diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c new file mode 100644 index 00000000000..a0e4e794890 --- /dev/null +++ b/sound/soc/samsung/dmaengine.c @@ -0,0 +1,78 @@ +/* + * dmaengine.c - Samsung dmaengine wrapper + * + * Author: Mark Brown <broonie@linaro.org> + * Copyright 2013 Linaro + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/amba/pl08x.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/dmaengine_pcm.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "dma.h" + +#ifdef CONFIG_ARCH_S3C64XX +#define filter_fn pl08x_filter_id +#else +#define filter_fn NULL +#endif + +static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .compat_filter_fn = filter_fn, +}; + +void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, + struct s3c_dma_params *playback, + struct s3c_dma_params *capture) +{ + struct snd_dmaengine_dai_dma_data *playback_data = NULL; + struct snd_dmaengine_dai_dma_data *capture_data = NULL; + + if (playback) { + playback_data = &playback->dma_data; + playback_data->filter_data = (void *)playback->channel; + playback_data->chan_name = playback->ch_name; + playback_data->addr = playback->dma_addr; + playback_data->addr_width = playback->dma_size; + } + if (capture) { + capture_data = &capture->dma_data; + capture_data->filter_data = (void *)capture->channel; + capture_data->chan_name = capture->ch_name; + capture_data->addr = capture->dma_addr; + capture_data->addr_width = capture->dma_size; + } + + snd_soc_dai_init_dma_data(dai, playback_data, capture_data); +} +EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); + +int samsung_asoc_dma_platform_register(struct device *dev) +{ + return devm_snd_dmaengine_pcm_register(dev, + &samsung_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME | + SND_DMAENGINE_PCM_FLAG_COMPAT); +} +EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); + +MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); +MODULE_DESCRIPTION("Samsung dmaengine ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index 415ad81999c..9506d761722 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -274,8 +274,8 @@ static int __init goni_init(void) return -ENOMEM; /* register voice DAI here */ - ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component, - &voice_dai, 1); + ret = devm_snd_soc_register_component(&goni_snd_device->dev, + &voice_component, &voice_dai, 1); if (ret) { platform_device_put(goni_snd_device); return ret; @@ -284,17 +284,14 @@ static int __init goni_init(void) platform_set_drvdata(goni_snd_device, &goni); ret = platform_device_add(goni_snd_device); - if (ret) { - snd_soc_unregister_component(&goni_snd_device->dev); + if (ret) platform_device_put(goni_snd_device); - } return ret; } static void __exit goni_exit(void) { - snd_soc_unregister_component(&goni_snd_device->dev); platform_device_unregister(goni_snd_device); } diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index fa91376e323..f2d7980d7dd 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -23,6 +23,7 @@ #include "regs-iis.h" #include <asm/mach-types.h> +#include <mach/gpio-samsung.h> #include "s3c24xx-i2s.h" static unsigned int rates[] = { @@ -65,10 +66,6 @@ static int h1940_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.rate_min = hw_rates.list[0]; - runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); @@ -93,7 +90,7 @@ static int h1940_hw_params(struct snd_pcm_substream *substream, div++; break; default: - dev_err(&rtd->dev, "%s: rate %d is not supported\n", + dev_err(rtd->dev, "%s: rate %d is not supported\n", __func__, rate); return -EINVAL; } @@ -179,12 +176,6 @@ static struct platform_device *s3c24xx_snd_device; static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int err; - - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hp_jack); @@ -198,6 +189,14 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int h1940_uda1380_card_remove(struct snd_soc_card *card) +{ + snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), + hp_jack_gpios); + + return 0; +} + /* s3c24xx digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link h1940_uda1380_dai[] = { { @@ -215,6 +214,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = { static struct snd_soc_card h1940_asoc = { .name = "h1940", .owner = THIS_MODULE, + .remove = h1940_uda1380_card_remove, .dai_link = h1940_uda1380_dai, .num_links = ARRAY_SIZE(h1940_uda1380_dai), @@ -266,8 +266,6 @@ err_out: static void __exit h1940_exit(void) { platform_device_unregister(s3c24xx_snd_device); - snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), - hp_jack_gpios); gpio_free(S3C_GPIO_END + 9); } diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index c0e6d9a19ef..821a5023100 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h @@ -31,6 +31,10 @@ #define I2SLVL1ADDR 0x34 #define I2SLVL2ADDR 0x38 #define I2SLVL3ADDR 0x3c +#define I2SSTR1 0x40 +#define I2SVER 0x44 +#define I2SFIC2 0x48 +#define I2STDM 0x4c #define CON_RSTCLR (1 << 31) #define CON_FRXOFSTATUS (1 << 26) @@ -95,24 +99,39 @@ #define MOD_RXONLY (1 << 8) #define MOD_TXRX (2 << 8) #define MOD_MASK (3 << 8) -#define MOD_LR_LLOW (0 << 7) -#define MOD_LR_RLOW (1 << 7) -#define MOD_SDF_IIS (0 << 5) -#define MOD_SDF_MSB (1 << 5) -#define MOD_SDF_LSB (2 << 5) -#define MOD_SDF_MASK (3 << 5) -#define MOD_RCLK_256FS (0 << 3) -#define MOD_RCLK_512FS (1 << 3) -#define MOD_RCLK_384FS (2 << 3) -#define MOD_RCLK_768FS (3 << 3) -#define MOD_RCLK_MASK (3 << 3) -#define MOD_BCLK_32FS (0 << 1) -#define MOD_BCLK_48FS (1 << 1) -#define MOD_BCLK_16FS (2 << 1) -#define MOD_BCLK_24FS (3 << 1) -#define MOD_BCLK_MASK (3 << 1) +#define MOD_LRP_SHIFT 7 +#define MOD_LR_LLOW 0 +#define MOD_LR_RLOW 1 +#define MOD_SDF_SHIFT 5 +#define MOD_SDF_IIS 0 +#define MOD_SDF_MSB 1 +#define MOD_SDF_LSB 2 +#define MOD_SDF_MASK 3 +#define MOD_RCLK_SHIFT 3 +#define MOD_RCLK_256FS 0 +#define MOD_RCLK_512FS 1 +#define MOD_RCLK_384FS 2 +#define MOD_RCLK_768FS 3 +#define MOD_RCLK_MASK 3 +#define MOD_BCLK_SHIFT 1 +#define MOD_BCLK_32FS 0 +#define MOD_BCLK_48FS 1 +#define MOD_BCLK_16FS 2 +#define MOD_BCLK_24FS 3 +#define MOD_BCLK_MASK 3 #define MOD_8BIT (1 << 0) +#define EXYNOS5420_MOD_LRP_SHIFT 15 +#define EXYNOS5420_MOD_SDF_SHIFT 6 +#define EXYNOS5420_MOD_RCLK_SHIFT 4 +#define EXYNOS5420_MOD_BCLK_SHIFT 0 +#define EXYNOS5420_MOD_BCLK_64FS 4 +#define EXYNOS5420_MOD_BCLK_96FS 5 +#define EXYNOS5420_MOD_BCLK_128FS 6 +#define EXYNOS5420_MOD_BCLK_192FS 7 +#define EXYNOS5420_MOD_BCLK_256FS 8 +#define EXYNOS5420_MOD_BCLK_MASK 0xf + #define MOD_CDCLKCON (1 << 12) #define PSR_PSREN (1 << 15) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 959c702235c..2ac76fa3e74 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -22,8 +22,6 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/dma.h> - #include <linux/platform_data/asoc-s3c.h> #include "dma.h" @@ -40,6 +38,7 @@ enum samsung_dai_type { struct samsung_i2s_dai_data { int dai_type; + u32 quirks; }; struct i2s_dai { @@ -198,7 +197,13 @@ static inline bool is_manager(struct i2s_dai *i2s) /* Read RCLK of I2S (in multiples of LRCLK) */ static inline unsigned get_rfs(struct i2s_dai *i2s) { - u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3; + u32 rfs; + + if (i2s->quirks & QUIRK_SUPPORTS_TDM) + rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT; + else + rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT); + rfs &= MOD_RCLK_MASK; switch (rfs) { case 3: return 768; @@ -212,21 +217,26 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) { u32 mod = readl(i2s->addr + I2SMOD); + int rfs_shift; - mod &= ~MOD_RCLK_MASK; + if (i2s->quirks & QUIRK_SUPPORTS_TDM) + rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT; + else + rfs_shift = MOD_RCLK_SHIFT; + mod &= ~(MOD_RCLK_MASK << rfs_shift); switch (rfs) { case 768: - mod |= MOD_RCLK_768FS; + mod |= (MOD_RCLK_768FS << rfs_shift); break; case 512: - mod |= MOD_RCLK_512FS; + mod |= (MOD_RCLK_512FS << rfs_shift); break; case 384: - mod |= MOD_RCLK_384FS; + mod |= (MOD_RCLK_384FS << rfs_shift); break; default: - mod |= MOD_RCLK_256FS; + mod |= (MOD_RCLK_256FS << rfs_shift); break; } @@ -236,9 +246,22 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) /* Read Bit-Clock of I2S (in multiples of LRCLK) */ static inline unsigned get_bfs(struct i2s_dai *i2s) { - u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3; + u32 bfs; + + if (i2s->quirks & QUIRK_SUPPORTS_TDM) { + bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT; + bfs &= EXYNOS5420_MOD_BCLK_MASK; + } else { + bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT; + bfs &= MOD_BCLK_MASK; + } switch (bfs) { + case 8: return 256; + case 7: return 192; + case 6: return 128; + case 5: return 96; + case 4: return 64; case 3: return 24; case 2: return 16; case 1: return 48; @@ -250,21 +273,50 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { u32 mod = readl(i2s->addr + I2SMOD); + int bfs_shift; + int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; - mod &= ~MOD_BCLK_MASK; + if (i2s->quirks & QUIRK_SUPPORTS_TDM) { + bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT; + mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift); + } else { + bfs_shift = MOD_BCLK_SHIFT; + mod &= ~(MOD_BCLK_MASK << bfs_shift); + } + + /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ + if (!tdm && bfs > 48) { + dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n"); + return; + } switch (bfs) { case 48: - mod |= MOD_BCLK_48FS; + mod |= (MOD_BCLK_48FS << bfs_shift); break; case 32: - mod |= MOD_BCLK_32FS; + mod |= (MOD_BCLK_32FS << bfs_shift); break; case 24: - mod |= MOD_BCLK_24FS; + mod |= (MOD_BCLK_24FS << bfs_shift); break; case 16: - mod |= MOD_BCLK_16FS; + mod |= (MOD_BCLK_16FS << bfs_shift); + break; + case 64: + mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift); + break; + case 96: + mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift); + break; + case 128: + mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift); + break; + case 192: + mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift); + break; + case 256: + mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift); break; default: dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n"); @@ -399,6 +451,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, u32 mod = readl(i2s->addr + I2SMOD); switch (clk_id) { + case SAMSUNG_I2S_OPCLK: + mod &= ~MOD_OPCLK_MASK; + mod |= dir; + break; case SAMSUNG_I2S_CDCLK: /* Shouldn't matter in GATING(CLOCK_IN) mode */ if (dir == SND_SOC_CLOCK_IN) @@ -432,7 +488,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, clk_id = 1; if (!any_active(i2s)) { - if (i2s->op_clk) { + if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || (!clk_id && (mod & MOD_IMS_SYSMUX))) { clk_disable_unprepare(i2s->op_clk); @@ -450,6 +506,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, else i2s->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk0"); + + if (WARN_ON(IS_ERR(i2s->op_clk))) + return PTR_ERR(i2s->op_clk); + clk_prepare_enable(i2s->op_clk); i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); @@ -491,20 +551,32 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, { struct i2s_dai *i2s = to_info(dai); u32 mod = readl(i2s->addr + I2SMOD); + int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; u32 tmp = 0; + if (i2s->quirks & QUIRK_SUPPORTS_TDM) { + lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; + sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; + } else { + lrp_shift = MOD_LRP_SHIFT; + sdf_shift = MOD_SDF_SHIFT; + } + + sdf_mask = MOD_SDF_MASK << sdf_shift; + lrp_rlow = MOD_LR_RLOW << lrp_shift; + /* Format is priority */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - tmp |= MOD_LR_RLOW; - tmp |= MOD_SDF_MSB; + tmp |= lrp_rlow; + tmp |= (MOD_SDF_MSB << sdf_shift); break; case SND_SOC_DAIFMT_LEFT_J: - tmp |= MOD_LR_RLOW; - tmp |= MOD_SDF_LSB; + tmp |= lrp_rlow; + tmp |= (MOD_SDF_LSB << sdf_shift); break; case SND_SOC_DAIFMT_I2S: - tmp |= MOD_SDF_IIS; + tmp |= (MOD_SDF_IIS << sdf_shift); break; default: dev_err(&i2s->pdev->dev, "Format not supported\n"); @@ -519,10 +591,10 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_NB_IF: - if (tmp & MOD_LR_RLOW) - tmp &= ~MOD_LR_RLOW; + if (tmp & lrp_rlow) + tmp &= ~lrp_rlow; else - tmp |= MOD_LR_RLOW; + tmp |= lrp_rlow; break; default: dev_err(&i2s->pdev->dev, "Polarity not supported\n"); @@ -544,15 +616,18 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } + /* + * Don't change the I2S mode if any controller is active on this + * channel. + */ if (any_active(i2s) && - ((mod & (MOD_SDF_MASK | MOD_LR_RLOW - | MOD_SLAVE)) != tmp)) { + ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; } - mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE); + mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); mod |= tmp; writel(mod, i2s->addr + I2SMOD); @@ -601,8 +676,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, if (is_manager(i2s)) mod &= ~MOD_BLC_MASK; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: + switch (params_width(params)) { + case 8: if (is_secondary(i2s)) mod |= MOD_BLCS_8BIT; else @@ -610,7 +685,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, if (is_manager(i2s)) mod |= MOD_BLC_8BIT; break; - case SNDRV_PCM_FORMAT_S16_LE: + case 16: if (is_secondary(i2s)) mod |= MOD_BLCS_16BIT; else @@ -618,7 +693,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, if (is_manager(i2s)) mod |= MOD_BLC_16BIT; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: if (is_secondary(i2s)) mod |= MOD_BLCS_24BIT; else @@ -633,12 +708,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } writel(mod, i2s->addr + I2SMOD); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_playback); - else - snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_capture); + samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); i2s->frmclk = params_rate(params); @@ -662,9 +732,6 @@ static int i2s_startup(struct snd_pcm_substream *substream, else i2s->mode |= DAI_MANAGER; - /* Enforce set_sysclk in Master mode */ - i2s->rclk_srcrate = 0; - if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) writel(CON_RSTCLR, i2s->addr + I2SCON); @@ -884,8 +951,11 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; - if (other && other->clk) /* If this is probe on secondary */ + if (other && other->clk) { /* If this is probe on secondary */ + samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, + NULL); goto probe_exit; + } i2s->addr = ioremap(i2s->base, 0x100); if (i2s->addr == NULL) { @@ -901,6 +971,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) } clk_prepare_enable(i2s->clk); + samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); + if (other) { other->addr = i2s->addr; other->clk = i2s->clk; @@ -917,6 +989,7 @@ probe_exit: /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; + i2s->rclk_srcrate = 0; i2s_txctrl(i2s, 0); i2s_rxctrl(i2s, 0); i2s_fifo(i2s, FIC_TXFLUSH); @@ -991,7 +1064,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops; i2s->i2s_dai_drv.suspend = i2s_suspend; i2s->i2s_dai_drv.resume = i2s_resume; - i2s->i2s_dai_drv.playback.channels_min = 2; + i2s->i2s_dai_drv.playback.channels_min = 1; i2s->i2s_dai_drv.playback.channels_max = 2; i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; @@ -1004,9 +1077,11 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) dev_set_drvdata(&i2s->pdev->dev, i2s); } else { /* Create a new platform_device for Secondary */ i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1); - if (IS_ERR(i2s->pdev)) + if (!i2s->pdev) return NULL; + i2s->pdev->dev.parent = &pdev->dev; + platform_set_drvdata(i2s->pdev, i2s); ret = platform_device_add(i2s->pdev); if (ret < 0) @@ -1018,18 +1093,18 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) static const struct of_device_id exynos_i2s_match[]; -static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) +static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( + struct platform_device *pdev) { #ifdef CONFIG_OF - struct samsung_i2s_dai_data *data; if (pdev->dev.of_node) { const struct of_device_id *match; match = of_match_node(exynos_i2s_match, pdev->dev.of_node); - data = (struct samsung_i2s_dai_data *) match->data; - return data->dai_type; + return match->data; } else #endif - return platform_get_device_id(pdev)->driver_data; + return (struct samsung_i2s_dai_data *) + platform_get_device_id(pdev)->driver_data; } #ifdef CONFIG_PM_RUNTIME @@ -1060,22 +1135,22 @@ static int samsung_i2s_probe(struct platform_device *pdev) struct resource *res; u32 regs_base, quirks = 0, idma_addr = 0; struct device_node *np = pdev->dev.of_node; - enum samsung_dai_type samsung_dai_type; + const struct samsung_i2s_dai_data *i2s_dai_data; int ret = 0; /* Call during Seconday interface registration */ - samsung_dai_type = samsung_i2s_get_driver_data(pdev); + i2s_dai_data = samsung_i2s_get_driver_data(pdev); - if (samsung_dai_type == TYPE_SEC) { + if (i2s_dai_data->dai_type == TYPE_SEC) { sec_dai = dev_get_drvdata(&pdev->dev); if (!sec_dai) { dev_err(&pdev->dev, "Unable to get drvdata\n"); return -EFAULT; } - snd_soc_register_component(&sec_dai->pdev->dev, - &samsung_i2s_component, - &sec_dai->i2s_dai_drv, 1); - asoc_dma_platform_register(&pdev->dev); + devm_snd_soc_register_component(&sec_dai->pdev->dev, + &samsung_i2s_component, + &sec_dai->i2s_dai_drv, 1); + samsung_asoc_dma_platform_register(&pdev->dev); return 0; } @@ -1115,15 +1190,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) idma_addr = i2s_cfg->idma_addr; } } else { - if (of_find_property(np, "samsung,supports-6ch", NULL)) - quirks |= QUIRK_PRI_6CHAN; - - if (of_find_property(np, "samsung,supports-secdai", NULL)) - quirks |= QUIRK_SEC_DAI; - - if (of_find_property(np, "samsung,supports-rstclr", NULL)) - quirks |= QUIRK_NEED_RSTCLR; - + quirks = i2s_dai_data->quirks; if (of_property_read_u32(np, "samsung,idma-addr", &idma_addr)) { if (quirks & QUIRK_SEC_DAI) { @@ -1150,10 +1217,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_playback.dma_addr = regs_base + I2STXD; pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; pri_dai->dma_playback.client = - (struct s3c2410_dma_client *)&pri_dai->dma_playback; + (struct s3c_dma_client *)&pri_dai->dma_playback; pri_dai->dma_playback.ch_name = "tx"; pri_dai->dma_capture.client = - (struct s3c2410_dma_client *)&pri_dai->dma_capture; + (struct s3c_dma_client *)&pri_dai->dma_capture; pri_dai->dma_capture.ch_name = "rx"; pri_dai->dma_playback.dma_size = 4; pri_dai->dma_capture.dma_size = 4; @@ -1172,7 +1239,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) } sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; sec_dai->dma_playback.client = - (struct s3c2410_dma_client *)&sec_dai->dma_playback; + (struct s3c_dma_client *)&sec_dai->dma_playback; sec_dai->dma_playback.ch_name = "tx-sec"; if (!np) { @@ -1195,16 +1262,18 @@ static int samsung_i2s_probe(struct platform_device *pdev) goto err; } - snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component, - &pri_dai->i2s_dai_drv, 1); + devm_snd_soc_register_component(&pri_dai->pdev->dev, + &samsung_i2s_component, + &pri_dai->i2s_dai_drv, 1); pm_runtime_enable(&pdev->dev); - asoc_dma_platform_register(&pdev->dev); + samsung_asoc_dma_platform_register(&pdev->dev); return 0; err: - release_mem_region(regs_base, resource_size(res)); + if (res) + release_mem_region(regs_base, resource_size(res)); return ret; } @@ -1230,33 +1299,56 @@ static int samsung_i2s_remove(struct platform_device *pdev) i2s->pri_dai = NULL; i2s->sec_dai = NULL; - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - return 0; } +static const struct samsung_i2s_dai_data i2sv3_dai_type = { + .dai_type = TYPE_PRI, + .quirks = QUIRK_NO_MUXPSR, +}; + +static const struct samsung_i2s_dai_data i2sv5_dai_type = { + .dai_type = TYPE_PRI, + .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR, +}; + +static const struct samsung_i2s_dai_data i2sv6_dai_type = { + .dai_type = TYPE_PRI, + .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | + QUIRK_SUPPORTS_TDM, +}; + +static const struct samsung_i2s_dai_data samsung_dai_type_pri = { + .dai_type = TYPE_PRI, +}; + +static const struct samsung_i2s_dai_data samsung_dai_type_sec = { + .dai_type = TYPE_SEC, +}; + static struct platform_device_id samsung_i2s_driver_ids[] = { { .name = "samsung-i2s", - .driver_data = TYPE_PRI, + .driver_data = (kernel_ulong_t)&samsung_dai_type_pri, }, { .name = "samsung-i2s-sec", - .driver_data = TYPE_SEC, + .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, }, {}, }; MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); #ifdef CONFIG_OF -static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = { - [TYPE_PRI] = { TYPE_PRI }, - [TYPE_SEC] = { TYPE_SEC }, -}; - static const struct of_device_id exynos_i2s_match[] = { - { .compatible = "samsung,i2s-v5", - .data = &samsung_i2s_dai_data_array[TYPE_PRI], + { + .compatible = "samsung,s3c6410-i2s", + .data = &i2sv3_dai_type, + }, { + .compatible = "samsung,s5pv210-i2s", + .data = &i2sv5_dai_type, + }, { + .compatible = "samsung,exynos5420-i2s", + .data = &i2sv6_dai_type, }, {}, }; diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h index 7966afc934d..21ff24e930d 100644 --- a/sound/soc/samsung/i2s.h +++ b/sound/soc/samsung/i2s.h @@ -18,5 +18,6 @@ #define SAMSUNG_I2S_RCLKSRC_0 0 #define SAMSUNG_I2S_RCLKSRC_1 1 #define SAMSUNG_I2S_CDCLK 2 +#define SAMSUNG_I2S_OPCLK 3 #endif /* __SND_SOC_SAMSUNG_I2S_H */ diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index ce1e1e16f25..8cc5770abb3 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -35,14 +35,6 @@ static const struct snd_pcm_hardware idma_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_U24_LE | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8, - .channels_min = 2, - .channels_max = 2, .buffer_bytes_max = MAX_IDMA_BUFFER, .period_bytes_min = 128, .period_bytes_max = MAX_IDMA_PERIOD, @@ -282,7 +274,7 @@ static irqreturn_t iis_irq(int irqno, void *dev_id) addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr; addr += prtd->periodsz; - addr %= (prtd->end - prtd->start); + addr %= (u32)(prtd->end - prtd->start); addr += idma.lp_tx_addr; writel(addr, idma.regs + I2SLVL0ADDR); @@ -383,18 +375,15 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static u64 idma_mask = DMA_BIT_MASK(32); - static int idma_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; - int ret = 0; + int ret; - if (!card->dev->dma_mask) - card->dev->dma_mask = &idma_mask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = preallocate_idma_buffer(pcm, @@ -424,13 +413,7 @@ static int asoc_idma_platform_probe(struct platform_device *pdev) if (idma_irq < 0) return idma_irq; - return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform); -} - -static int asoc_idma_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &asoc_idma_platform); } static struct platform_driver asoc_idma_driver = { @@ -440,7 +423,6 @@ static struct platform_driver asoc_idma_driver = { }, .probe = asoc_idma_platform_probe, - .remove = asoc_idma_platform_remove, }; module_platform_driver(asoc_idma_driver); diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index bfb91f34a22..840787e63cb 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -304,23 +304,12 @@ static int littlemill_probe(struct platform_device *pdev) card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - return ret; - } - - return 0; -} - -static int littlemill_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - snd_soc_unregister_card(card); - - return 0; + return ret; } static struct platform_driver littlemill_driver = { @@ -330,7 +319,6 @@ static struct platform_driver littlemill_driver = { .pm = &snd_soc_pm_ops, }, .probe = littlemill_probe, - .remove = littlemill_remove, }; module_platform_driver(littlemill_driver); diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 570cf522950..bd5f0d643a8 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -187,23 +187,12 @@ static int lowland_probe(struct platform_device *pdev) card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - return ret; - } - - return 0; -} - -static int lowland_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - snd_soc_unregister_card(card); - - return 0; + return ret; } static struct platform_driver lowland_driver = { @@ -213,7 +202,6 @@ static struct platform_driver lowland_driver = { .pm = &snd_soc_pm_ops, }, .probe = lowland_probe, - .remove = lowland_remove, }; module_platform_driver(lowland_driver); diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 807db417d23..9b4a09f14b6 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -20,6 +20,7 @@ #include <sound/soc.h> +#include <mach/gpio-samsung.h> #include <asm/mach-types.h> #include "regs-iis.h" @@ -191,44 +192,6 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, }; -/* Shared routes and controls */ - -static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { - SND_SOC_DAPM_LINE("GSM Line Out", NULL), - SND_SOC_DAPM_LINE("GSM Line In", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Handset Mic", NULL), -}; - -static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { - /* Connections to the GSM Module */ - {"GSM Line Out", NULL, "MONO1"}, - {"GSM Line Out", NULL, "MONO2"}, - {"RXP", NULL, "GSM Line In"}, - {"RXN", NULL, "GSM Line In"}, - - /* Connections to Headset */ - {"MIC1", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Headset Mic"}, - - /* Call Mic */ - {"MIC2", NULL, "Mic Bias"}, - {"MIC2N", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Handset Mic"}, - - /* Connect the ALC pins */ - {"ACIN", NULL, "ACOP"}, -}; - -static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { - SOC_DAPM_PIN_SWITCH("GSM Line Out"), - SOC_DAPM_PIN_SWITCH("GSM Line In"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Handset Mic"), -}; - -/* GTA02 specific routes and controls */ - static int gta02_speaker_enabled; static int lm4853_set_spk(struct snd_kcontrol *kcontrol, @@ -256,7 +219,34 @@ static int lm4853_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { +static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { + SND_SOC_DAPM_LINE("GSM Line Out", NULL), + SND_SOC_DAPM_LINE("GSM Line In", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_SPK("Handset Spk", NULL), + SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), +}; + +static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { + /* Connections to the GSM Module */ + {"GSM Line Out", NULL, "MONO1"}, + {"GSM Line Out", NULL, "MONO2"}, + {"RXP", NULL, "GSM Line In"}, + {"RXN", NULL, "GSM Line In"}, + + /* Connections to Headset */ + {"MIC1", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Headset Mic"}, + + /* Call Mic */ + {"MIC2", NULL, "Mic Bias"}, + {"MIC2N", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Handset Mic"}, + + /* Connect the ALC pins */ + {"ACIN", NULL, "ACOP"}, + /* Connections to the amp */ {"Stereo Out", NULL, "LOUT1"}, {"Stereo Out", NULL, "ROUT1"}, @@ -266,7 +256,11 @@ static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { {"Handset Spk", NULL, "ROUT2"}, }; -static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { +static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { + SOC_DAPM_PIN_SWITCH("GSM Line Out"), + SOC_DAPM_PIN_SWITCH("GSM Line In"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Handset Mic"), SOC_DAPM_PIN_SWITCH("Handset Spk"), SOC_DAPM_PIN_SWITCH("Stereo Out"), @@ -275,86 +269,25 @@ static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { lm4853_set_spk), }; -static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Handset Spk", NULL), - SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), -}; - -static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, - ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, - ARRAY_SIZE(neo1973_gta02_routes)); - if (ret) - return ret; - - ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls, - ARRAY_SIZE(neo1973_gta02_wm8753_controls)); - if (ret) - return ret; - - snd_soc_dapm_disable_pin(dapm, "Stereo Out"); - snd_soc_dapm_disable_pin(dapm, "Handset Spk"); - snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); - snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); - - return 0; -} - static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; - - /* set up NC codec pins */ - snd_soc_dapm_nc_pin(dapm, "OUT3"); - snd_soc_dapm_nc_pin(dapm, "OUT4"); - snd_soc_dapm_nc_pin(dapm, "LINE1"); - snd_soc_dapm_nc_pin(dapm, "LINE2"); - - /* Add neo1973 specific widgets */ - ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, - ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); - if (ret) - return ret; - - /* add neo1973 specific controls */ - ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls, - ARRAY_SIZE(neo1973_wm8753_controls)); - if (ret) - return ret; - - /* set up neo1973 specific audio routes */ - ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, - ARRAY_SIZE(neo1973_wm8753_routes)); - if (ret) - return ret; + struct snd_soc_card *card = rtd->card; /* set endpoints to default off mode */ - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Handset Mic"); + snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out"); + snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In"); + snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic"); + snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic"); + snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out"); + snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk"); /* allow audio paths from the GSM modem to run during suspend */ - snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); - snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); - snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); - snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); - - if (machine_is_neo1973_gta02()) { - ret = neo1973_gta02_wm8753_init(codec); - if (ret) - return ret; - } + snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out"); + snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk"); return 0; } @@ -408,6 +341,14 @@ static struct snd_soc_card neo1973 = { .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), .codec_conf = neo1973_codec_conf, .num_configs = ARRAY_SIZE(neo1973_codec_conf), + + .controls = neo1973_wm8753_controls, + .num_controls = ARRAY_SIZE(neo1973_wm8753_controls), + .dapm_widgets = neo1973_wm8753_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets), + .dapm_routes = neo1973_wm8753_routes, + .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes), + .fully_routed = true, }; static struct platform_device *neo1973_snd_device; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 1566afe9ef5..4c5f97fe45c 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -20,7 +20,6 @@ #include <sound/pcm_params.h> #include <linux/platform_data/asoc-s3c.h> -#include <mach/dma.h> #include "dma.h" #include "pcm.h" @@ -132,11 +131,11 @@ struct s3c_pcm_info { struct s3c_dma_params *dma_capture; }; -static struct s3c2410_dma_client s3c_pcm_dma_client_out = { +static struct s3c_dma_client s3c_pcm_dma_client_out = { .name = "PCM Stereo out" }; -static struct s3c2410_dma_client s3c_pcm_dma_client_in = { +static struct s3c_dma_client s3c_pcm_dma_client_in = { .name = "PCM Stereo in" }; @@ -275,7 +274,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai); - struct s3c_dma_params *dma_data; void __iomem *regs = pcm->regs; struct clk *clk; int sclk_div, sync_div; @@ -284,16 +282,9 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, dev_dbg(pcm->dev, "Entered %s\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dma_data = pcm->dma_playback; - else - dma_data = pcm->dma_capture; - - snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data); - /* Strictly check for sample size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: break; default: return -EINVAL; @@ -461,10 +452,20 @@ static const struct snd_soc_dai_ops s3c_pcm_dai_ops = { .set_fmt = s3c_pcm_set_fmt, }; +static int s3c_pcm_dai_probe(struct snd_soc_dai *dai) +{ + struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, pcm->dma_playback, pcm->dma_capture); + + return 0; +} + #define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 #define S3C_PCM_DAI_DECLARE \ .symmetric_rates = 1, \ + .probe = s3c_pcm_dai_probe, \ .ops = &s3c_pcm_dai_ops, \ .playback = { \ .channels_min = 2, \ @@ -541,7 +542,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) /* Default is 128fs */ pcm->sclk_per_fs = 128; - pcm->cclk = clk_get(&pdev->dev, "audio-bus"); + pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus"); if (IS_ERR(pcm->cclk)) { dev_err(&pdev->dev, "failed to get audio-bus\n"); ret = PTR_ERR(pcm->cclk); @@ -566,7 +567,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) goto err3; } - pcm->pclk = clk_get(&pdev->dev, "pcm"); + pcm->pclk = devm_clk_get(&pdev->dev, "pcm"); if (IS_ERR(pcm->pclk)) { dev_err(&pdev->dev, "failed to get pcm_clock\n"); ret = -ENOENT; @@ -587,33 +588,29 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component, + ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component, &s3c_pcm_dai[pdev->id], 1); if (ret != 0) { dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); goto err5; } - ret = asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err6; + goto err5; } return 0; -err6: - snd_soc_unregister_component(&pdev->dev); err5: clk_disable_unprepare(pcm->pclk); - clk_put(pcm->pclk); err4: iounmap(pcm->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: clk_disable_unprepare(pcm->cclk); - clk_put(pcm->cclk); err1: return ret; } @@ -623,9 +620,6 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev) struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; struct resource *mem_res; - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - pm_runtime_disable(&pdev->dev); iounmap(pcm->regs); @@ -635,8 +629,6 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev) clk_disable_unprepare(pcm->cclk); clk_disable_unprepare(pcm->pclk); - clk_put(pcm->pclk); - clk_put(pcm->cclk); return 0; } diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h index c3878f7acb8..a71be45bbff 100644 --- a/sound/soc/samsung/regs-ac97.h +++ b/sound/soc/samsung/regs-ac97.h @@ -1,5 +1,4 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-ac97.h - * +/* * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/ * @@ -10,8 +9,8 @@ * S3C2440 AC97 Controller */ -#ifndef __ASM_ARCH_REGS_AC97_H -#define __ASM_ARCH_REGS_AC97_H __FILE__ +#ifndef __SAMSUNG_REGS_AC97_H__ +#define __SAMSUNG_REGS_AC97_H__ #define S3C_AC97_GLBCTRL (0x00) @@ -64,4 +63,4 @@ #define S3C_AC97_PCM_DATA (0x18) #define S3C_AC97_MIC_DATA (0x1C) -#endif /* __ASM_ARCH_REGS_AC97_H */ +#endif /* __SAMSUNG_REGS_AC97_H__ */ diff --git a/sound/soc/samsung/regs-iis.h b/sound/soc/samsung/regs-iis.h index a18d35e7a73..dc6cbbe9c4f 100644 --- a/sound/soc/samsung/regs-iis.h +++ b/sound/soc/samsung/regs-iis.h @@ -1,5 +1,4 @@ -/* arch/arm/plat-samsung/include/plat/regs-iis.h - * +/* * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/ * @@ -10,8 +9,8 @@ * S3C2410 IIS register definition */ -#ifndef __ASM_ARCH_REGS_IIS_H -#define __ASM_ARCH_REGS_IIS_H +#ifndef __SAMSUNG_REGS_IIS_H__ +#define __SAMSUNG_REGS_IIS_H__ #define S3C2410_IISCON (0x00) @@ -67,4 +66,4 @@ #define S3C2410_IISFIFO (0x10) -#endif /* __ASM_ARCH_REGS_IIS_H */ +#endif /* __SAMSUNG_REGS_IIS_H__ */ diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 704460a3700..37688ebbb2b 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -24,12 +24,14 @@ #include <sound/soc.h> #include <sound/jack.h> +#include <mach/gpio-samsung.h> #include "regs-iis.h" #include <asm/mach-types.h> #include "s3c24xx-i2s.h" static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); +static int rx1950_uda1380_card_remove(struct snd_soc_card *card); static int rx1950_startup(struct snd_pcm_substream *substream); static int rx1950_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); @@ -115,6 +117,7 @@ static const struct snd_soc_dapm_route audio_map[] = { static struct snd_soc_card rx1950_asoc = { .name = "rx1950", .owner = THIS_MODULE, + .remove = rx1950_uda1380_card_remove, .dai_link = rx1950_uda1380_dai, .num_links = ARRAY_SIZE(rx1950_uda1380_dai), @@ -130,10 +133,6 @@ static int rx1950_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.rate_min = hw_rates.list[0]; - runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); @@ -224,12 +223,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int err; - - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hp_jack); @@ -243,6 +236,14 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int rx1950_uda1380_card_remove(struct snd_soc_card *card) +{ + snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), + hp_jack_gpios); + + return 0; +} + static int __init rx1950_init(void) { int ret; @@ -287,8 +288,6 @@ err_gpio: static void __exit rx1950_exit(void) { platform_device_unregister(s3c24xx_snd_device); - snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), - hp_jack_gpios); gpio_free(S3C2410_GPA(1)); } diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index e5e81b11100..0ff4bbe23af 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -31,11 +31,7 @@ #undef S3C_IIS_V2_SUPPORTED #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \ - || defined(CONFIG_CPU_S5PV210) -#define S3C_IIS_V2_SUPPORTED -#endif - -#ifdef CONFIG_PLAT_S3C64XX + || defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210) #define S3C_IIS_V2_SUPPORTED #endif @@ -326,13 +322,13 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream, iismod &= ~S3C64XX_IISMOD_BLC_MASK; /* Sample size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: + switch (params_width(params)) { + case 8: iismod |= S3C64XX_IISMOD_BLC_8BIT; break; - case SNDRV_PCM_FORMAT_S16_LE: + case 16: break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: iismod |= S3C64XX_IISMOD_BLC_24BIT; break; } @@ -733,7 +729,7 @@ int s3c_i2sv2_register_component(struct device *dev, int id, struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv) { - struct snd_soc_dai_ops *ops = drv->ops; + struct snd_soc_dai_ops *ops = dai_drv->ops; ops->trigger = s3c2412_i2s_trigger; if (!ops->hw_params) @@ -746,10 +742,10 @@ int s3c_i2sv2_register_component(struct device *dev, int id, if (!ops->delay) ops->delay = s3c2412_i2s_delay; - drv->suspend = s3c2412_i2s_suspend; - drv->resume = s3c2412_i2s_resume; + dai_drv->suspend = s3c2412_i2s_suspend; + dai_drv->resume = s3c2412_i2s_resume; - return snd_soc_register_component(dev, cmp_drv, dai_drv, 1); + return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1); } EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component); diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 47e23864ea7..08c059be910 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -26,16 +26,18 @@ #include <sound/pcm_params.h> #include <mach/dma.h> +#include <mach/gpio-samsung.h> +#include <plat/gpio-cfg.h> #include "dma.h" #include "regs-i2s-v2.h" #include "s3c2412-i2s.h" -static struct s3c2410_dma_client s3c2412_dma_client_out = { +static struct s3c_dma_client s3c2412_dma_client_out = { .name = "I2S PCM Stereo out" }; -static struct s3c2410_dma_client s3c2412_dma_client_in = { +static struct s3c_dma_client s3c2412_dma_client_in = { .name = "I2S PCM Stereo in" }; @@ -118,11 +120,11 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: + switch (params_width(params)) { + case 8: iismod |= S3C2412_IISMOD_8BIT; break; - case SNDRV_PCM_FORMAT_S16_LE: + case 16: iismod &= ~S3C2412_IISMOD_8BIT; break; } @@ -176,28 +178,15 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = asoc_dma_platform_register(&pdev->dev); - if (ret) { + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) pr_err("failed to register the DMA: %d\n", ret); - goto err; - } - return 0; -err: - snd_soc_unregister_component(&pdev->dev); return ret; } -static int s3c2412_iis_dev_remove(struct platform_device *pdev) -{ - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - return 0; -} - static struct platform_driver s3c2412_iis_driver = { .probe = s3c2412_iis_dev_probe, - .remove = s3c2412_iis_dev_remove, .driver = { .name = "s3c2412-iis", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 8b3414551a6..9aba9fb7df0 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -24,16 +24,18 @@ #include <sound/pcm_params.h> #include <mach/dma.h> +#include <mach/gpio-samsung.h> +#include <plat/gpio-cfg.h> #include "regs-iis.h" #include "dma.h" #include "s3c24xx-i2s.h" -static struct s3c2410_dma_client s3c24xx_dma_client_out = { +static struct s3c_dma_client s3c24xx_dma_client_out = { .name = "I2S PCM Stereo out" }; -static struct s3c2410_dma_client s3c24xx_dma_client_in = { +static struct s3c_dma_client s3c24xx_dma_client_in = { .name = "I2S PCM Stereo in" }; @@ -246,12 +248,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params r: IISMOD: %x\n", iismod); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: + switch (params_width(params)) { + case 8: iismod &= ~S3C2410_IISMOD_16BIT; dma_data->dma_size = 1; break; - case SNDRV_PCM_FORMAT_S16_LE: + case 16: iismod |= S3C2410_IISMOD_16BIT; dma_data->dma_size = 2; break; @@ -473,35 +475,22 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; - ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, - &s3c24xx_i2s_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); if (ret) { pr_err("failed to register the dai\n"); return ret; } - ret = asoc_dma_platform_register(&pdev->dev); - if (ret) { + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) pr_err("failed to register the dma: %d\n", ret); - goto err; - } - return 0; -err: - snd_soc_unregister_component(&pdev->dev); return ret; } -static int s3c24xx_iis_dev_remove(struct platform_device *pdev) -{ - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - return 0; -} - static struct platform_driver s3c24xx_iis_driver = { .probe = s3c24xx_iis_dev_probe, - .remove = s3c24xx_iis_dev_remove, .driver = { .name = "s3c24xx-iis", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index d8a0543cae5..2d30b7b6818 100644 --- a/sound/soc/samsung/s3c24xx_simtec_hermes.c +++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c @@ -63,14 +63,6 @@ static const struct snd_soc_dapm_route base_map[] = { */ static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Line Out"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - simtec_audio_init(rtd); return 0; diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index 1ac0d7a63a3..83f6c7d49cd 100644 --- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c @@ -52,14 +52,6 @@ static const struct snd_soc_dapm_route base_map[] = { */ static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Line Out"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - simtec_audio_init(rtd); return 0; diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index 58ae3237ef6..9b0ffacab79 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -19,6 +19,7 @@ #include <sound/soc.h> #include <sound/jack.h> +#include <mach/gpio-samsung.h> #include <asm/mach-types.h> #include "i2s.h" @@ -161,8 +162,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_nc_pin(dapm, "ROUT1"); /* set endpoints to default off mode */ - snd_soc_dapm_enable_pin(dapm, "Internal Speaker"); - snd_soc_dapm_enable_pin(dapm, "Internal Mic"); snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); /* Headphone jack detection */ @@ -183,6 +182,14 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) return err; } +static int smartq_wm8987_card_remove(struct snd_soc_card *card) +{ + snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), + smartq_jack_gpios); + + return 0; +} + static struct snd_soc_dai_link smartq_dai[] = { { .name = "wm8987", @@ -199,6 +206,7 @@ static struct snd_soc_dai_link smartq_dai[] = { static struct snd_soc_card snd_soc_smartq = { .name = "SmartQ", .owner = THIS_MODULE, + .remove = smartq_wm8987_card_remove, .dai_link = smartq_dai, .num_links = ARRAY_SIZE(smartq_dai), @@ -260,8 +268,6 @@ err_unregister_device: static void __exit smartq_exit(void) { gpio_free(S3C64XX_GPK(12)); - snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), - smartq_jack_gpios); platform_device_unregister(smartq_snd_device); } diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 7a16b32ed67..b1a519f83b2 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -37,13 +37,11 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, unsigned int pll_out; int bfs, rfs, ret; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: + switch (params_width(params)) { + case 8: bfs = 16; break; - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S16_LE: + case 16: bfs = 32; break; default: diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index 23a9204b106..e119aaa91c2 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -164,19 +164,11 @@ static int snd_smdk_probe(struct platform_device *pdev) xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; smdk_pcm.dev = &pdev->dev; - ret = snd_soc_register_card(&smdk_pcm); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); - return ret; - } - return 0; -} - -static int snd_smdk_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&smdk_pcm); - return 0; + return ret; } static struct platform_driver snd_smdk_driver = { @@ -185,7 +177,6 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = snd_smdk_remove, }; module_platform_driver(snd_smdk_driver); diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 581ea4a06fc..3d6272a8cad 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -9,8 +9,10 @@ #include "../codecs/wm8994.h" #include <sound/pcm_params.h> +#include <sound/soc.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> /* * Default CFG switch settings to use this driver: @@ -37,35 +39,31 @@ /* SMDK has a 16.934MHZ crystal attached to WM8994 */ #define SMDK_WM8994_FREQ 16934000 +struct smdk_wm8994_data { + int mclk1_rate; +}; + +/* Default SMDKs */ +static struct smdk_wm8994_data smdk_board_data = { + .mclk1_rate = SMDK_WM8994_FREQ, +}; + static int smdk_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; unsigned int pll_out; int ret; /* AIF1CLK should be >=3MHz for optimal performance */ - if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) + if (params_width(params) == 24) pll_out = params_rate(params) * 384; else if (params_rate(params) == 8000 || params_rate(params) == 11025) pll_out = params_rate(params) * 512; else pll_out = params_rate(params) * 256; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, SMDK_WM8994_FREQ, pll_out); if (ret < 0) @@ -91,18 +89,6 @@ static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - /* HeadPhone */ - snd_soc_dapm_enable_pin(dapm, "HPOUT1R"); - snd_soc_dapm_enable_pin(dapm, "HPOUT1L"); - - /* MicIn */ - snd_soc_dapm_enable_pin(dapm, "IN1LN"); - snd_soc_dapm_enable_pin(dapm, "IN1RN"); - - /* LineIn */ - snd_soc_dapm_enable_pin(dapm, "IN2LN"); - snd_soc_dapm_enable_pin(dapm, "IN2RN"); - /* Other pins NC */ snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); @@ -131,6 +117,8 @@ static struct snd_soc_dai_link smdk_dai[] = { .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .init = smdk_wm8994_init_paiftx, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &smdk_ops, }, { /* Sec_Fifo Playback i/f */ .name = "Sec_FIFO TX", @@ -139,6 +127,8 @@ static struct snd_soc_dai_link smdk_dai[] = { .codec_dai_name = "wm8994-aif1", .platform_name = "samsung-i2s-sec", .codec_name = "wm8994-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, .ops = &smdk_ops, }, }; @@ -150,15 +140,26 @@ static struct snd_soc_card smdk = { .num_links = ARRAY_SIZE(smdk_dai), }; +static const struct of_device_id samsung_wm8994_of_match[] = { + { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); static int smdk_audio_probe(struct platform_device *pdev) { int ret; struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &smdk; + struct smdk_wm8994_data *board; + const struct of_device_id *id; card->dev = &pdev->dev; + board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL); + if (!board) + return -ENOMEM; + if (np) { smdk_dai[0].cpu_dai_name = NULL; smdk_dai[0].cpu_of_node = of_parse_phandle(np, @@ -173,7 +174,13 @@ static int smdk_audio_probe(struct platform_device *pdev) smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; } - ret = snd_soc_register_card(card); + id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev); + if (id) + *board = *((struct smdk_wm8994_data *)id->data); + + platform_set_drvdata(pdev, board); + + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); @@ -181,35 +188,18 @@ static int smdk_audio_probe(struct platform_device *pdev) return ret; } -static int smdk_audio_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id samsung_wm8994_of_match[] = { - { .compatible = "samsung,smdk-wm8994", }, - {}, -}; -MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); -#endif /* CONFIG_OF */ - static struct platform_driver smdk_audio_driver = { .driver = { - .name = "smdk-audio", + .name = "smdk-audio-wm8994", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_wm8994_of_match), + .pm = &snd_soc_pm_ops, }, .probe = smdk_audio_probe, - .remove = smdk_audio_remove, }; module_platform_driver(smdk_audio_driver); MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:smdk-audio"); +MODULE_ALIAS("platform:smdk-audio-wm8994"); diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 0c84ca09961..b6c09979be1 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -134,19 +134,11 @@ static int snd_smdk_probe(struct platform_device *pdev) int ret = 0; smdk_pcm.dev = &pdev->dev; - ret = snd_soc_register_card(&smdk_pcm); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); - return ret; - } - return 0; -} - -static int snd_smdk_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&smdk_pcm); - return 0; + return ret; } static struct platform_driver snd_smdk_driver = { @@ -155,7 +147,6 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = snd_smdk_remove, }; module_platform_driver(snd_smdk_driver); diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c new file mode 100644 index 00000000000..014c177840b --- /dev/null +++ b/sound/soc/samsung/snow.c @@ -0,0 +1,123 @@ +/* + * ASoC machine driver for Snow boards + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include <sound/soc.h> + +#include "i2s.h" + +#define FIN_PLL_RATE 24000000 + +static struct snd_soc_dai_link snow_dai[] = { + { + .name = "Primary", + .stream_name = "Primary", + .codec_dai_name = "HiFi", + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, +}; + +static int snow_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; + int ret; + + /* Set the MCLK rate for the codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + FIN_PLL_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* Select I2S Bus clock to set RCLK and BCLK */ + ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_card snow_snd = { + .name = "Snow-I2S", + .dai_link = snow_dai, + .num_links = ARRAY_SIZE(snow_dai), + + .late_probe = snow_late_probe, +}; + +static int snow_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snow_snd; + struct device_node *i2s_node, *codec_node; + int i, ret; + + i2s_node = of_parse_phandle(pdev->dev.of_node, + "samsung,i2s-controller", 0); + if (!i2s_node) { + dev_err(&pdev->dev, + "Property 'i2s-controller' missing or invalid\n"); + return -EINVAL; + } + + codec_node = of_parse_phandle(pdev->dev.of_node, + "samsung,audio-codec", 0); + if (!codec_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(snow_dai); i++) { + snow_dai[i].codec_of_node = codec_node; + snow_dai[i].cpu_of_node = i2s_node; + snow_dai[i].platform_of_node = i2s_node; + } + + card->dev = &pdev->dev; + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + return ret; + } + + return ret; +} + +static const struct of_device_id snow_of_match[] = { + { .compatible = "google,snow-audio-max98090", }, + { .compatible = "google,snow-audio-max98095", }, + {}, +}; + +static struct platform_driver snow_driver = { + .driver = { + .name = "snow-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = snow_of_match, + }, + .probe = snow_probe, +}; + +module_platform_driver(snow_driver); + +MODULE_DESCRIPTION("ALSA SoC Audio machine driver for Snow"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 2e5ebb2f198..d9ffc48fce5 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -18,7 +18,6 @@ #include <sound/pcm_params.h> #include <linux/platform_data/asoc-s3c.h> -#include <mach/dma.h> #include "dma.h" #include "spdif.h" @@ -94,7 +93,7 @@ struct samsung_spdif_info { struct s3c_dma_params *dma_playback; }; -static struct s3c2410_dma_client spdif_dma_client_out = { +static struct s3c_dma_client spdif_dma_client_out = { .name = "S/PDIF Stereo out", }; @@ -212,8 +211,8 @@ static int spdif_hw_params(struct snd_pcm_substream *substream, con |= CON_PCM_DATA; con &= ~CON_PCM_MASK; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: con |= CON_PCM_16BIT; break; default: @@ -395,7 +394,7 @@ static int spdif_probe(struct platform_device *pdev) spin_lock_init(&spdif->lock); - spdif->pclk = clk_get(&pdev->dev, "spdif"); + spdif->pclk = devm_clk_get(&pdev->dev, "spdif"); if (IS_ERR(spdif->pclk)) { dev_err(&pdev->dev, "failed to get peri-clock\n"); ret = -ENOENT; @@ -403,7 +402,7 @@ static int spdif_probe(struct platform_device *pdev) } clk_prepare_enable(spdif->pclk); - spdif->sclk = clk_get(&pdev->dev, "sclk_spdif"); + spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif"); if (IS_ERR(spdif->sclk)) { dev_err(&pdev->dev, "failed to get internal source clock\n"); ret = -ENOENT; @@ -428,8 +427,8 @@ static int spdif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); - ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component, - &samsung_spdif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &samsung_spdif_component, &samsung_spdif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "fail to register dai\n"); goto err4; @@ -442,25 +441,21 @@ static int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; - ret = asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); - goto err5; + goto err4; } return 0; -err5: - snd_soc_unregister_component(&pdev->dev); err4: iounmap(spdif->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: clk_disable_unprepare(spdif->sclk); - clk_put(spdif->sclk); err1: clk_disable_unprepare(spdif->pclk); - clk_put(spdif->pclk); err0: return ret; } @@ -470,9 +465,6 @@ static int spdif_remove(struct platform_device *pdev) struct samsung_spdif_info *spdif = &spdif_info; struct resource *mem_res; - asoc_dma_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - iounmap(spdif->regs); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -480,9 +472,7 @@ static int spdif_remove(struct platform_device *pdev) release_mem_region(mem_res->start, resource_size(mem_res)); clk_disable_unprepare(spdif->sclk); - clk_put(spdif->sclk); clk_disable_unprepare(spdif->pclk); - clk_put(spdif->pclk); return 0; } diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 57df90d6b7c..9902efcb8ea 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -327,23 +327,12 @@ static int speyside_probe(struct platform_device *pdev) card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - return ret; - } - - return 0; -} - -static int speyside_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - snd_soc_unregister_card(card); - - return 0; + return ret; } static struct platform_driver speyside_driver = { @@ -353,7 +342,6 @@ static struct platform_driver speyside_driver = { .pm = &snd_soc_pm_ops, }, .probe = speyside_probe, - .remove = speyside_remove, }; module_platform_driver(speyside_driver); diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index f21ff608a81..6a2b9f14d62 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -44,6 +44,8 @@ static int tobermory_set_bias_level(struct snd_soc_card *card, SND_SOC_CLOCK_IN); if (ret < 0) { pr_err("Failed to set SYSCLK: %d\n", ret); + snd_soc_dai_set_pll(codec_dai, WM8962_FLL, + 0, 0, 0); return ret; } } @@ -221,23 +223,12 @@ static int tobermory_probe(struct platform_device *pdev) card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret) { + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); - return ret; - } - - return 0; -} - -static int tobermory_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - snd_soc_unregister_card(card); - - return 0; + return ret; } static struct platform_driver tobermory_driver = { @@ -247,7 +238,6 @@ static struct platform_driver tobermory_driver = { .pm = &snd_soc_pm_ops, }, .probe = tobermory_probe, - .remove = tobermory_remove, }; module_platform_driver(tobermory_driver); |
