diff options
Diffstat (limited to 'sound/soc/samsung')
42 files changed, 1772 insertions, 801 deletions
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index fe3995ce9b3..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 ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4 - select S3C64XX_DMA if ARCH_S3C64XX + depends on PLAT_SAMSUNG 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 @@ -35,12 +44,11 @@ config SND_SAMSUNG_I2S tristate config SND_SOC_SAMSUNG_NEO1973_WM8753 - tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)" - depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02) + tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)" + depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02 select SND_S3C24XX_I2S select SND_SOC_WM8753 - select SND_SOC_LM4857 if MACH_NEO1973_GTA01 - select SND_SOC_DFBMCS320 + select SND_SOC_BT_SCO help Say Y here to enable audio support for the Openmoko Neo1973 Smartphones. @@ -51,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,8 +72,8 @@ 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 && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212) - depends on I2C=y && GENERIC_HARDIRQS + depends on SND_SOC_SAMSUNG + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_I2S @@ -107,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 @@ -129,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 @@ -137,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" @@ -152,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 @@ -162,7 +171,7 @@ config SND_SOC_GONI_AQUILA_WM8994 config SND_SOC_SAMSUNG_SMDK_SPDIF tristate "SoC S/PDIF Audio support for SMDK" - depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212) + depends on SND_SOC_SAMSUNG select SND_SAMSUNG_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. @@ -170,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,8 +187,8 @@ 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 && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212) - depends on I2C=y && GENERIC_HARDIRQS + depends on SND_SOC_SAMSUNG + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_PCM @@ -191,14 +201,25 @@ config SND_SOC_SPEYSIDE select SND_SAMSUNG_I2S select SND_SOC_WM8996 select SND_SOC_WM9081 + select SND_SOC_WM0010 select SND_SOC_WM1250_EV1 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 && MFD_ARIZONA + select SND_SAMSUNG_I2S + select SND_SOC_WM5102 + select SND_SOC_WM5110 + select SND_SOC_WM9081 + select SND_SOC_WM0010 + select SND_SOC_WM1250_EV1 + config SND_SOC_LOWLAND tristate "Audio support for Wolfson Lowland" depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 @@ -212,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 9d03beb40c8..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 @@ -42,6 +45,7 @@ snd-soc-speyside-objs := speyside.o snd-soc-tobermory-objs := tobermory.o snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o +snd-soc-bells-objs := bells.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -55,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 @@ -65,3 +70,4 @@ obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o +obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 3d04c1fa678..68d9303047e 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -20,8 +20,8 @@ #include <sound/soc.h> #include <mach/dma.h> -#include <plat/regs-ac97.h> -#include <plat/audio.h> +#include "regs-ac97.h" +#include <linux/platform_data/asoc-s3c.h> #include "dma.h" @@ -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); @@ -214,31 +214,12 @@ static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) return IRQ_HANDLED; } -struct snd_ac97_bus_ops soc_ac97_ops = { +static struct snd_ac97_bus_ops s3c_ac97_ops = { .read = s3c_ac97_read, .write = s3c_ac97_write, .warm_reset = s3c_ac97_warm_reset, .reset = s3c_ac97_cold_reset, }; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -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) @@ -280,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) { @@ -330,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", @@ -355,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] = { @@ -366,11 +345,16 @@ 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, }, }; -static __devinit int s3c_ac97_probe(struct platform_device *pdev) +static const struct snd_soc_component_driver s3c_ac97_component = { + .name = "s3c-ac97", +}; + +static int s3c_ac97_probe(struct platform_device *pdev) { struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; struct s3c_audio_pdata *ac97_pdata; @@ -401,23 +385,16 @@ static __devinit 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; } - if (!request_mem_region(mem_res->start, - resource_size(mem_res), "ac97")) { - dev_err(&pdev->dev, "Unable to request register region\n"); - return -EBUSY; - } + 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); s3c_ac97_pcm_out.channel = dmatx_res->start; s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; @@ -429,20 +406,13 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) init_completion(&s3c_ac97.done); mutex_init(&s3c_ac97.lock); - s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res)); - if (s3c_ac97.regs == NULL) { - dev_err(&pdev->dev, "Unable to ioremap register region\n"); - ret = -ENXIO; - goto err1; - } - - s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97"); + s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97"); if (IS_ERR(s3c_ac97.ac97_clk)) { dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n"); ret = -ENODEV; goto err2; } - clk_enable(s3c_ac97.ac97_clk); + clk_prepare_enable(s3c_ac97.ac97_clk); if (ac97_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); @@ -457,52 +427,51 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev) goto err4; } - ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai, - ARRAY_SIZE(s3c_ac97_dai)); + ret = snd_soc_set_ac97_ops(&s3c_ac97_ops); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); + goto err4; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component, + s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); if (ret) goto err5; - return 0; + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err5; + } + return 0; err5: free_irq(irq_res->start, NULL); err4: err3: - clk_disable(s3c_ac97.ac97_clk); - clk_put(s3c_ac97.ac97_clk); + clk_disable_unprepare(s3c_ac97.ac97_clk); err2: - iounmap(s3c_ac97.regs); -err1: - release_mem_region(mem_res->start, resource_size(mem_res)); - + snd_soc_set_ac97_ops(NULL); return ret; } -static __devexit int s3c_ac97_remove(struct platform_device *pdev) +static int s3c_ac97_remove(struct platform_device *pdev) { - struct resource *mem_res, *irq_res; - - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai)); + struct resource *irq_res; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (irq_res) free_irq(irq_res->start, NULL); - clk_disable(s3c_ac97.ac97_clk); - clk_put(s3c_ac97.ac97_clk); - - iounmap(s3c_ac97.regs); - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mem_res) - release_mem_region(mem_res->start, resource_size(mem_res)); + clk_disable_unprepare(s3c_ac97.ac97_clk); + snd_soc_set_ac97_ops(NULL); return 0; } static struct platform_driver s3c_ac97_driver = { .probe = s3c_ac97_probe, - .remove = __devexit_p(s3c_ac97_remove), + .remove = s3c_ac97_remove, .driver = { .name = "samsung-ac97", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c new file mode 100644 index 00000000000..5b21207cf55 --- /dev/null +++ b/sound/soc/samsung/bells.c @@ -0,0 +1,459 @@ +/* + * Bells audio support + * + * Copyright 2012 Wolfson Microelectronics + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <linux/gpio.h> +#include <linux/module.h> + +#include "../codecs/wm5102.h" +#include "../codecs/wm9081.h" + +/* BCLK2 is fixed at this currently */ +#define BCLK2_RATE (64 * 8000) + +/* + * Expect a 24.576MHz crystal if one is fitted (the driver will function + * if this is not fitted). + */ +#define MCLK_RATE 24576000 + +#define SYS_AUDIO_RATE 44100 +#define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512) + +#define DAI_AP_DSP 0 +#define DAI_DSP_CODEC 1 +#define DAI_CODEC_CP 2 +#define DAI_CODEC_SUB 3 + +struct bells_drvdata { + int sysclk_rate; + int asyncclk_rate; +}; + +static struct bells_drvdata wm2200_drvdata = { + .sysclk_rate = 22579200, +}; + +static struct bells_drvdata wm5102_drvdata = { + .sysclk_rate = 45158400, + .asyncclk_rate = 49152000, +}; + +static struct bells_drvdata wm5110_drvdata = { + .sysclk_rate = 135475200, + .asyncclk_rate = 147456000, +}; + +static int bells_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + bells->sysclk_rate); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + + if (bells->asyncclk_rate) { + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + ARIZONA_FLL_SRC_AIF2BCLK, + BCLK2_RATE, + bells->asyncclk_rate); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + } + break; + + default: + break; + } + + return 0; +} + +static int bells_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct bells_drvdata *bells = card->drvdata; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } + + if (bells->asyncclk_rate) { + ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + 0, 0, 0); + if (ret < 0) { + pr_err("Failed to stop FLL: %d\n", ret); + return ret; + } + } + break; + + default: + break; + } + + dapm->bias_level = level; + + return 0; +} + +static int bells_late_probe(struct snd_soc_card *card) +{ + struct bells_drvdata *bells = card->drvdata; + struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; + struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; + struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_dai *aif2_dai; + struct snd_soc_dai *aif3_dai; + struct snd_soc_dai *wm9081_dai; + int ret; + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, + bells->sysclk_rate, + SND_SOC_CLOCK_IN); + if (ret != 0) { + dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); + if (ret != 0) { + dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, + SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); + if (ret != 0) + dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + + if (card->num_rtd == DAI_CODEC_CP) + return 0; + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, + bells->asyncclk_rate, + SND_SOC_CLOCK_IN); + if (ret != 0) { + dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret); + return ret; + } + + aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + if (ret != 0) { + dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); + return ret; + } + + if (card->num_rtd == DAI_CODEC_SUB) + return 0; + + aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; + wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; + + ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret != 0) { + dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, + 0, SYS_MCLK_RATE, 0); + if (ret != 0) { + dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_pcm_stream baseband_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 2, + .channels_max = 2, +}; + +static const struct snd_soc_pcm_stream sub_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = SYS_AUDIO_RATE, + .rate_max = SYS_AUDIO_RATE, + .channels_min = 2, + .channels_max = 2, +}; + +static struct snd_soc_dai_link bells_dai_wm2200[] = { + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_dai_name = "wm2200", + .codec_name = "wm2200.1-003a", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link bells_dai_wm5102[] = { + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_dai_name = "wm5102-aif1", + .codec_name = "wm5102-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, + }, + { + .name = "Baseband", + .stream_name = "Baseband", + .cpu_dai_name = "wm5102-aif2", + .codec_dai_name = "wm1250-ev1", + .codec_name = "wm1250-ev1.1-0027", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + .params = &baseband_params, + }, + { + .name = "Sub", + .stream_name = "Sub", + .cpu_dai_name = "wm5102-aif3", + .codec_dai_name = "wm9081-hifi", + .codec_name = "wm9081.1-006c", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .params = &sub_params, + }, +}; + +static struct snd_soc_dai_link bells_dai_wm5110[] = { + { + .name = "CPU-DSP", + .stream_name = "CPU-DSP", + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", + .codec_dai_name = "wm5110-aif1", + .codec_name = "wm5110-codec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .params = &sub_params, + .ignore_suspend = 1, + }, + { + .name = "Baseband", + .stream_name = "Baseband", + .cpu_dai_name = "wm5110-aif2", + .codec_dai_name = "wm1250-ev1", + .codec_name = "wm1250-ev1.1-0027", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + .params = &baseband_params, + }, + { + .name = "Sub", + .stream_name = "Sub", + .cpu_dai_name = "wm5110-aif3", + .codec_dai_name = "wm9081-hifi", + .codec_name = "wm9081.1-006c", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .ignore_suspend = 1, + .params = &sub_params, + }, +}; + +static struct snd_soc_codec_conf bells_codec_conf[] = { + { + .dev_name = "wm9081.1-006c", + .name_prefix = "Sub", + }, +}; + +static struct snd_soc_dapm_widget bells_widgets[] = { + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static struct snd_soc_dapm_route bells_routes[] = { + { "Sub CLK_SYS", NULL, "OPCLK" }, + { "CLKIN", NULL, "OPCLK" }, + + { "DMIC", NULL, "MICBIAS2" }, + { "IN2L", NULL, "DMIC" }, + { "IN2R", NULL, "DMIC" }, +}; + +static struct snd_soc_card bells_cards[] = { + { + .name = "Bells WM2200", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm2200, + .num_links = ARRAY_SIZE(bells_dai_wm2200), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_widgets = bells_widgets, + .num_dapm_widgets = ARRAY_SIZE(bells_widgets), + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm2200_drvdata, + }, + { + .name = "Bells WM5102", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm5102, + .num_links = ARRAY_SIZE(bells_dai_wm5102), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_widgets = bells_widgets, + .num_dapm_widgets = ARRAY_SIZE(bells_widgets), + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5102_drvdata, + }, + { + .name = "Bells WM5110", + .owner = THIS_MODULE, + .dai_link = bells_dai_wm5110, + .num_links = ARRAY_SIZE(bells_dai_wm5110), + .codec_conf = bells_codec_conf, + .num_configs = ARRAY_SIZE(bells_codec_conf), + + .late_probe = bells_late_probe, + + .dapm_widgets = bells_widgets, + .num_dapm_widgets = ARRAY_SIZE(bells_widgets), + .dapm_routes = bells_routes, + .num_dapm_routes = ARRAY_SIZE(bells_routes), + + .set_bias_level = bells_set_bias_level, + .set_bias_level_post = bells_set_bias_level_post, + + .drvdata = &wm5110_drvdata, + }, +}; + + +static int bells_probe(struct platform_device *pdev) +{ + int ret; + + bells_cards[pdev->id].dev = &pdev->dev; + + 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; +} + +static struct platform_driver bells_driver = { + .driver = { + .name = "bells", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = bells_probe, +}; + +module_platform_driver(bells_driver); + +MODULE_DESCRIPTION("Bells audio support"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bells"); diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index ddc6cde14e2..d9dc7bcc033 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -34,15 +34,7 @@ static const struct snd_pcm_hardware dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | - 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_U8 | - SNDRV_PCM_FMTBIT_S8, - .channels_min = 2, - .channels_max = 2, + SNDRV_PCM_INFO_MMAP_VALID, .buffer_bytes_max = 128*1024, .period_bytes_min = PAGE_SIZE, .period_bytes_max = PAGE_SIZE*2, @@ -74,7 +66,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream) struct runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; unsigned int limit; - struct samsung_dma_prep_info dma_info; + struct samsung_dma_prep dma_info; pr_debug("Entered %s\n", __func__); @@ -92,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); @@ -146,7 +145,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - struct samsung_dma_info dma_info; + struct samsung_dma_req req; + struct samsung_dma_config config; pr_debug("Entered %s\n", __func__); @@ -166,16 +166,22 @@ static int dma_hw_params(struct snd_pcm_substream *substream, prtd->params->ops = samsung_dma_get_ops(); - dma_info.cap = (samsung_dma_has_circular() ? + req.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); - dma_info.client = prtd->params->client; - dma_info.direction = + req.client = prtd->params->client; + config.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); - dma_info.width = prtd->params->dma_size; - dma_info.fifo = prtd->params->dma_addr; + config.width = prtd->params->dma_size; + config.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( - prtd->params->channel, &dma_info); + 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); } snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); @@ -246,15 +252,11 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->state |= ST_RUNNING; prtd->params->ops->trigger(prtd->params->ch); break; case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->state &= ~ST_RUNNING; prtd->params->ops->stop(prtd->params->ch); break; @@ -398,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, @@ -436,30 +435,20 @@ static struct snd_soc_platform_driver samsung_asoc_platform = { .pcm_free = dma_free_dma_buffers, }; -static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev) +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(&pdev->dev, &samsung_asoc_platform); + snd_soc_dai_init_dma_data(dai, playback, capture); } +EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); -static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev) +int samsung_asoc_dma_platform_register(struct device *dev) { - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(dev, &samsung_asoc_platform); } - -static struct platform_driver asoc_dma_driver = { - .driver = { - .name = "samsung-audio", - .owner = THIS_MODULE, - }, - - .probe = samsung_asoc_platform_probe, - .remove = __devexit_p(samsung_asoc_platform_remove), -}; - -module_platform_driver(asoc_dma_driver); +EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-audio"); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 7d1ead77ef2..070ab0f0960 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -12,13 +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; }; +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 c23c2ae91f5..9506d761722 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, }; +static const struct snd_soc_component_driver voice_component = { + .name = "goni-voice", +}; + static struct snd_soc_ops goni_voice_ops = { .hw_params = goni_voice_hw_params, }; @@ -228,7 +232,7 @@ static struct snd_soc_dai_link goni_dai[] = { .stream_name = "WM8994 HiFi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, .ops = &goni_hifi_ops, @@ -270,7 +274,8 @@ static int __init goni_init(void) return -ENOMEM; /* register voice DAI here */ - ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai); + 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; @@ -279,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_dai(&goni_snd_device->dev); + if (ret) platform_device_put(goni_snd_device); - } return ret; } static void __exit goni_exit(void) { - snd_soc_unregister_dai(&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 6e3257717c5..f2d7980d7dd 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -20,10 +20,10 @@ #include <sound/soc.h> #include <sound/jack.h> -#include <plat/regs-iis.h> -#include <mach/h1940-latch.h> +#include "regs-iis.h" #include <asm/mach-types.h> +#include <mach/gpio-samsung.h> #include "s3c24xx-i2s.h" static unsigned int rates[] = { @@ -66,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); @@ -94,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; } @@ -147,9 +143,9 @@ static int h1940_spk_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(H1940_LATCH_AUDIO_POWER, 1); + gpio_set_value(S3C_GPIO_END + 9, 1); else - gpio_set_value(H1940_LATCH_AUDIO_POWER, 0); + gpio_set_value(S3C_GPIO_END + 9, 0); return 0; } @@ -180,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); @@ -199,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[] = { { @@ -207,7 +205,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = h1940_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &h1940_ops, }, @@ -216,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), @@ -233,11 +232,11 @@ static int __init h1940_init(void) return -ENODEV; /* configure some gpios */ - ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power"); + ret = gpio_request(S3C_GPIO_END + 9, "speaker-power"); if (ret) goto err_out; - ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0); + ret = gpio_direction_output(S3C_GPIO_END + 9, 0); if (ret) goto err_gpio; @@ -258,7 +257,7 @@ static int __init h1940_init(void) err_plat: platform_device_put(s3c24xx_snd_device); err_gpio: - gpio_free(H1940_LATCH_AUDIO_POWER); + gpio_free(S3C_GPIO_END + 9); err_out: return ret; @@ -267,9 +266,7 @@ 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(H1940_LATCH_AUDIO_POWER); + gpio_free(S3C_GPIO_END + 9); } module_init(h1940_init); 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 6ac7b8281a0..2ac76fa3e74 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -15,12 +15,14 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <sound/soc.h> #include <sound/pcm_params.h> -#include <plat/audio.h> +#include <linux/platform_data/asoc-s3c.h> #include "dma.h" #include "idma.h" @@ -29,6 +31,16 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +enum samsung_dai_type { + TYPE_PRI, + TYPE_SEC, +}; + +struct samsung_i2s_dai_data { + int dai_type; + u32 quirks; +}; + struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; @@ -49,8 +61,6 @@ struct i2s_dai { struct clk *clk; /* Clock for generating I2S signals */ struct clk *op_clk; - /* Array of clock names for op_clk */ - const char **src_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ @@ -68,6 +78,7 @@ struct i2s_dai { u32 suspend_i2smod; u32 suspend_i2scon; u32 suspend_i2spsr; + unsigned long gpios[7]; /* i2s gpio line numbers */ }; /* Lock for cross i/f checks */ @@ -186,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; @@ -200,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; } @@ -224,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; @@ -238,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; + + 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); + } - mod &= ~MOD_BCLK_MASK; + /* 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"); @@ -387,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) @@ -420,10 +488,10 @@ 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(i2s->op_clk); + clk_disable_unprepare(i2s->op_clk); clk_put(i2s->op_clk); } else { i2s->rclk_srcrate = @@ -432,9 +500,17 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, } } - i2s->op_clk = clk_get(&i2s->pdev->dev, - i2s->src_clk[clk_id]); - clk_enable(i2s->op_clk); + if (clk_id) + i2s->op_clk = clk_get(&i2s->pdev->dev, + "i2s_opclk1"); + 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); /* Over-ride the other's */ @@ -475,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"); @@ -503,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"); @@ -528,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); @@ -585,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 @@ -594,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 @@ -602,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 @@ -617,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); @@ -646,8 +732,8 @@ 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); spin_unlock_irqrestore(&lock, flags); @@ -723,13 +809,13 @@ static int config_setup(struct i2s_dai *i2s) return -EAGAIN; } - /* Don't bother RFS, BFS & PSR in Slave mode */ - if (is_slave(i2s)) - return 0; - set_bfs(i2s, bfs); set_rfs(i2s, rfs); + /* Don't bother with PSR in Slave mode */ + if (is_slave(i2s)) + return 0; + if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { psr = i2s->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); @@ -865,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) { @@ -880,7 +969,9 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) iounmap(i2s->addr); return -ENOENT; } - clk_enable(i2s->clk); + clk_prepare_enable(i2s->clk); + + samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); if (other) { other->addr = i2s->addr; @@ -898,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); @@ -922,7 +1014,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(0, i2s->addr + I2SCON); - clk_disable(i2s->clk); + clk_disable_unprepare(i2s->clk); clk_put(i2s->clk); iounmap(i2s->addr); @@ -944,16 +1036,20 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { .delay = i2s_delay, }; +static const struct snd_soc_component_driver samsung_i2s_component = { + .name = "samsung-i2s", +}; + #define SAMSUNG_I2S_RATES SNDRV_PCM_RATE_8000_96000 #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static __devinit -struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) +static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) { struct i2s_dai *i2s; + int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); if (i2s == NULL) @@ -968,7 +1064,7 @@ 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; @@ -978,63 +1074,132 @@ struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) i2s->i2s_dai_drv.capture.channels_max = 2; i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES; i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; + dev_set_drvdata(&i2s->pdev->dev, i2s); } else { /* Create a new platform_device for Secondary */ - i2s->pdev = platform_device_register_resndata(NULL, - pdev->name, pdev->id + SAMSUNG_I2S_SECOFF, - NULL, 0, NULL, 0); - if (IS_ERR(i2s->pdev)) + i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1); + if (!i2s->pdev) return NULL; - } - /* Pre-assign snd_soc_dai_set_drvdata */ - dev_set_drvdata(&i2s->pdev->dev, i2s); + i2s->pdev->dev.parent = &pdev->dev; + + platform_set_drvdata(i2s->pdev, i2s); + ret = platform_device_add(i2s->pdev); + if (ret < 0) + return NULL; + } return i2s; } -static __devinit int samsung_i2s_probe(struct platform_device *pdev) +static const struct of_device_id exynos_i2s_match[]; + +static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( + struct platform_device *pdev) +{ +#ifdef CONFIG_OF + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(exynos_i2s_match, pdev->dev.of_node); + return match->data; + } else +#endif + return (struct samsung_i2s_dai_data *) + platform_get_device_id(pdev)->driver_data; +} + +#ifdef CONFIG_PM_RUNTIME +static int i2s_runtime_suspend(struct device *dev) +{ + struct i2s_dai *i2s = dev_get_drvdata(dev); + + clk_disable_unprepare(i2s->clk); + + return 0; +} + +static int i2s_runtime_resume(struct device *dev) +{ + struct i2s_dai *i2s = dev_get_drvdata(dev); + + clk_prepare_enable(i2s->clk); + + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +static int samsung_i2s_probe(struct platform_device *pdev) { - u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan; struct i2s_dai *pri_dai, *sec_dai = NULL; - struct s3c_audio_pdata *i2s_pdata; - struct samsung_i2s *i2s_cfg; + struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; + struct samsung_i2s *i2s_cfg = NULL; struct resource *res; - u32 regs_base, quirks; + u32 regs_base, quirks = 0, idma_addr = 0; + struct device_node *np = pdev->dev.of_node; + const struct samsung_i2s_dai_data *i2s_dai_data; int ret = 0; /* Call during Seconday interface registration */ - if (pdev->id >= SAMSUNG_I2S_SECOFF) { + i2s_dai_data = samsung_i2s_get_driver_data(pdev); + + if (i2s_dai_data->dai_type == TYPE_SEC) { sec_dai = dev_get_drvdata(&pdev->dev); - snd_soc_register_dai(&sec_dai->pdev->dev, - &sec_dai->i2s_dai_drv); + if (!sec_dai) { + dev_err(&pdev->dev, "Unable to get drvdata\n"); + return -EFAULT; + } + 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; } - i2s_pdata = pdev->dev.platform_data; - if (i2s_pdata == NULL) { - dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); - return -EINVAL; + pri_dai = i2s_alloc_dai(pdev, false); + if (!pri_dai) { + dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); + return -ENOMEM; } - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n"); - return -ENXIO; - } - dma_pl_chan = res->start; + if (!np) { + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(&pdev->dev, + "Unable to get I2S-TX dma resource\n"); + return -ENXIO; + } + pri_dai->dma_playback.channel = res->start; - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n"); - return -ENXIO; - } - dma_cp_chan = res->start; + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(&pdev->dev, + "Unable to get I2S-RX dma resource\n"); + return -ENXIO; + } + pri_dai->dma_capture.channel = res->start; - res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (res) - dma_pl_sec_chan = res->start; - else - dma_pl_sec_chan = 0; + if (i2s_pdata == NULL) { + dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); + return -EINVAL; + } + + if (&i2s_pdata->type) + i2s_cfg = &i2s_pdata->type.i2s; + + if (i2s_cfg) { + quirks = i2s_cfg->quirks; + idma_addr = i2s_cfg->idma_addr; + } + } else { + quirks = i2s_dai_data->quirks; + if (of_property_read_u32(np, "samsung,idma-addr", + &idma_addr)) { + if (quirks & QUIRK_SEC_DAI) { + dev_err(&pdev->dev, "idma address is not"\ + "specified"); + return -EINVAL; + } + } + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -1049,25 +1214,14 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) } regs_base = res->start; - i2s_cfg = &i2s_pdata->type.i2s; - quirks = i2s_cfg->quirks; - - pri_dai = i2s_alloc_dai(pdev, false); - if (!pri_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); - ret = -ENOMEM; - goto err; - } - 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; - pri_dai->dma_playback.channel = dma_pl_chan; - pri_dai->dma_capture.channel = dma_cp_chan; - pri_dai->src_clk = i2s_cfg->src_clk; + (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; pri_dai->base = regs_base; @@ -1085,36 +1239,46 @@ static __devinit 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; - /* Use iDMA always if SysDMA not provided */ - sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1; - sec_dai->src_clk = i2s_cfg->src_clk; + (struct s3c_dma_client *)&sec_dai->dma_playback; + sec_dai->dma_playback.ch_name = "tx-sec"; + + if (!np) { + res = platform_get_resource(pdev, IORESOURCE_DMA, 2); + if (res) + sec_dai->dma_playback.channel = res->start; + } + sec_dai->dma_playback.dma_size = 4; sec_dai->base = regs_base; sec_dai->quirks = quirks; - sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr; + sec_dai->idma_playback.dma_addr = idma_addr; sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; } - if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { + if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); ret = -EINVAL; goto err; } - snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); + devm_snd_soc_register_component(&pri_dai->pdev->dev, + &samsung_i2s_component, + &pri_dai->i2s_dai_drv, 1); pm_runtime_enable(&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; } -static __devexit int samsung_i2s_remove(struct platform_device *pdev) +static int samsung_i2s_remove(struct platform_device *pdev) { struct i2s_dai *i2s, *other; struct resource *res; @@ -1135,17 +1299,76 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev) i2s->pri_dai = NULL; i2s->sec_dai = NULL; - snd_soc_unregister_dai(&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 = (kernel_ulong_t)&samsung_dai_type_pri, + }, { + .name = "samsung-i2s-sec", + .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); + +#ifdef CONFIG_OF +static const struct of_device_id exynos_i2s_match[] = { + { + .compatible = "samsung,s3c6410-i2s", + .data = &i2sv3_dai_type, + }, { + .compatible = "samsung,s5pv210-i2s", + .data = &i2sv5_dai_type, + }, { + .compatible = "samsung,exynos5420-i2s", + .data = &i2sv6_dai_type, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_i2s_match); +#endif + +static const struct dev_pm_ops samsung_i2s_pm = { + SET_RUNTIME_PM_OPS(i2s_runtime_suspend, + i2s_runtime_resume, NULL) +}; + static struct platform_driver samsung_i2s_driver = { .probe = samsung_i2s_probe, - .remove = __devexit_p(samsung_i2s_remove), + .remove = samsung_i2s_remove, + .id_table = samsung_i2s_driver_ids, .driver = { .name = "samsung-i2s", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(exynos_i2s_match), + .pm = &samsung_i2s_pm, }, }; diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h index d420a7ca56c..21ff24e930d 100644 --- a/sound/soc/samsung/i2s.h +++ b/sound/soc/samsung/i2s.h @@ -13,17 +13,11 @@ #ifndef __SND_SOC_SAMSUNG_I2S_H #define __SND_SOC_SAMSUNG_I2S_H -/* - * Maximum number of I2S blocks that any SoC can have. - * The secondary interface of a CPU dai(if there exists any), - * is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF] - */ -#define SAMSUNG_I2S_SECOFF 4 - #define SAMSUNG_I2S_DIV_BCLK 1 #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 c227c3163ca..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, @@ -68,6 +60,8 @@ static struct idma_info { dma_addr_t lp_tx_addr; } idma; +static int idma_irq; + static void idma_getpos(dma_addr_t *src) { *src = idma.lp_tx_addr + @@ -255,7 +249,6 @@ static int idma_mmap(struct snd_pcm_substream *substream, /* From snd_pcm_lib_mmap_iomem */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO; size = vma->vm_end - vma->vm_start; offset = vma->vm_pgoff << PAGE_SHIFT; ret = io_remap_pfn_range(vma, vma->vm_start, @@ -281,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); @@ -305,7 +298,7 @@ static int idma_open(struct snd_pcm_substream *substream) if (prtd == NULL) return -ENOMEM; - ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd); + ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd); if (ret < 0) { pr_err("fail to claim i2s irq , ret = %d\n", ret); kfree(prtd); @@ -324,7 +317,7 @@ static int idma_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct idma_ctrl *prtd = runtime->private_data; - free_irq(IRQ_I2S0, prtd); + free_irq(idma_irq, prtd); if (!prtd) pr_err("idma_close called with prtd == NULL\n"); @@ -382,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, @@ -409,6 +399,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr) idma.regs = regs; idma.lp_tx_addr = addr; } +EXPORT_SYMBOL_GPL(idma_reg_addr_init); static struct snd_soc_platform_driver asoc_idma_platform = { .ops = &idma_ops, @@ -416,15 +407,13 @@ static struct snd_soc_platform_driver asoc_idma_platform = { .pcm_free = idma_free, }; -static int __devinit asoc_idma_platform_probe(struct platform_device *pdev) +static int asoc_idma_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform); -} + idma_irq = platform_get_irq(pdev, 0); + if (idma_irq < 0) + return idma_irq; -static int __devexit 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 = { @@ -434,7 +423,6 @@ static struct platform_driver asoc_idma_driver = { }, .probe = asoc_idma_platform_probe, - .remove = __devexit_p(asoc_idma_platform_remove), }; module_platform_driver(asoc_idma_driver); diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index 1578663a1fa..b5f6abd9d22 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c @@ -118,7 +118,7 @@ static struct snd_soc_dai_link jive_dai = { .stream_name = "WM8750", .cpu_dai_name = "s3c2412-i2s", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c2412-i2s", .codec_name = "wm8750.0-001a", .init = jive_wm8750_init, .ops = &jive_ops, diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index c82c646b8a0..840787e63cb 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -145,7 +145,7 @@ static struct snd_soc_dai_link littlemill_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8994-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -211,6 +211,11 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("WM1250 Input"), + SOC_DAPM_PIN_SWITCH("WM1250 Output"), +}; + static struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -265,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card) return ret; /* This will check device compatibility itself */ - wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL); + wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL, NULL, NULL); /* As will this */ wm8994_mic_detect(codec, &littlemill_headset, 1); @@ -282,6 +287,8 @@ static struct snd_soc_card littlemill = { .set_bias_level = littlemill_set_bias_level, .set_bias_level_post = littlemill_set_bias_level_post, + .controls = controls, + .num_controls = ARRAY_SIZE(controls), .dapm_widgets = widgets, .num_dapm_widgets = ARRAY_SIZE(widgets), .dapm_routes = audio_paths, @@ -290,30 +297,19 @@ static struct snd_soc_card littlemill = { .late_probe = littlemill_late_probe, }; -static __devinit int littlemill_probe(struct platform_device *pdev) +static int littlemill_probe(struct platform_device *pdev) { struct snd_soc_card *card = &littlemill; int ret; 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 __devexit 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 = { @@ -323,7 +319,6 @@ static struct platform_driver littlemill_driver = { .pm = &snd_soc_pm_ops, }, .probe = littlemill_probe, - .remove = __devexit_p(littlemill_remove), }; module_platform_driver(littlemill_driver); diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c index 69c4a5934a4..9342fc270c2 100644 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ b/sound/soc/samsung/ln2440sbc_alc650.c @@ -28,7 +28,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 6abf341c4a2..bd5f0d643a8 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -99,7 +99,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm5100-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm5100.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -180,30 +180,19 @@ static struct snd_soc_card lowland = { .num_dapm_routes = ARRAY_SIZE(audio_paths), }; -static __devinit int lowland_probe(struct platform_device *pdev) +static int lowland_probe(struct platform_device *pdev) { struct snd_soc_card *card = &lowland; int ret; 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 __devexit 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 = __devexit_p(lowland_remove), }; module_platform_driver(lowland_driver); diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 321d51134e4..9b4a09f14b6 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -20,9 +20,9 @@ #include <sound/soc.h> +#include <mach/gpio-samsung.h> #include <asm/mach-types.h> -#include <plat/regs-iis.h> -#include <mach/gta02.h> +#include "regs-iis.h" #include "../codecs/wm8753.h" #include "s3c24xx-i2s.h" @@ -192,13 +192,40 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, }; -/* Shared routes and controls */ +static int gta02_speaker_enabled; + +static int lm4853_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + gta02_speaker_enabled = ucontrol->value.integer.value[0]; + + gpio_set_value(S3C2410_GPJ(2), !gta02_speaker_enabled); + + return 0; +} + +static int lm4853_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = gta02_speaker_enabled; + return 0; +} + +static int lm4853_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpio_set_value(S3C2410_GPJ(1), SND_SOC_DAPM_EVENT_OFF(event)); + + return 0; +} 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[] = { @@ -219,45 +246,7 @@ static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { /* 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, - struct snd_ctl_elem_value *ucontrol) -{ - gta02_speaker_enabled = ucontrol->value.integer.value[0]; - - gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); - - return 0; -} - -static int lm4853_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = gta02_speaker_enabled; - return 0; -} -static int lm4853_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); - - return 0; -} - -static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { /* Connections to the amp */ {"Stereo Out", NULL, "LOUT1"}, {"Stereo Out", NULL, "ROUT1"}, @@ -267,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"), @@ -276,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; } @@ -364,7 +296,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", .stream_name = "WM8753 HiFi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", .codec_name = "wm8753.0-001a", @@ -374,7 +306,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { { /* Voice via BT */ .name = "Bluetooth", .stream_name = "Voice", - .cpu_dai_name = "dfbmcs320-pcm", + .cpu_dai_name = "bt-sco-pcm", .codec_dai_name = "wm8753-voice", .codec_name = "wm8753.0-001a", .ops = &neo1973_voice_ops, @@ -396,8 +328,8 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = { }; static const struct gpio neo1973_gta02_gpios[] = { - { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, - { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, + { S3C2410_GPJ(2), GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, + { S3C2410_GPJ(1), GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, }; static struct snd_soc_card neo1973 = { @@ -409,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 b7b2a1f9142..4c5f97fe45c 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -19,8 +19,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <plat/audio.h> -#include <plat/dma.h> +#include <linux/platform_data/asoc-s3c.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, \ @@ -490,7 +491,11 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = { }, }; -static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) +static const struct snd_soc_component_driver s3c_pcm_component = { + .name = "s3c-pcm", +}; + +static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; struct resource *mem_res, *dmatx_res, *dmarx_res; @@ -537,13 +542,13 @@ static __devinit 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); goto err1; } - clk_enable(pcm->cclk); + clk_prepare_enable(pcm->cclk); /* record our pcm structure for later use in the callbacks */ dev_set_drvdata(&pdev->dev, pcm); @@ -562,13 +567,13 @@ static __devinit 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; goto err4; } - clk_enable(pcm->pclk); + clk_prepare_enable(pcm->pclk); s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start + S3C_PCM_RXFIFO; @@ -583,35 +588,38 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]); + 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 = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); + goto err5; + } + return 0; err5: - clk_disable(pcm->pclk); - clk_put(pcm->pclk); + clk_disable_unprepare(pcm->pclk); err4: iounmap(pcm->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(pcm->cclk); - clk_put(pcm->cclk); + clk_disable_unprepare(pcm->cclk); err1: return ret; } -static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) +static int s3c_pcm_dev_remove(struct platform_device *pdev) { struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; struct resource *mem_res; - snd_soc_unregister_dai(&pdev->dev); - pm_runtime_disable(&pdev->dev); iounmap(pcm->regs); @@ -619,17 +627,15 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(pcm->cclk); - clk_disable(pcm->pclk); - clk_put(pcm->pclk); - clk_put(pcm->cclk); + clk_disable_unprepare(pcm->cclk); + clk_disable_unprepare(pcm->pclk); return 0; } static struct platform_driver s3c_pcm_driver = { .probe = s3c_pcm_dev_probe, - .remove = __devexit_p(s3c_pcm_dev_remove), + .remove = s3c_pcm_dev_remove, .driver = { .name = "samsung-pcm", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h new file mode 100644 index 00000000000..a71be45bbff --- /dev/null +++ b/sound/soc/samsung/regs-ac97.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + * + * 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. + * + * S3C2440 AC97 Controller +*/ + +#ifndef __SAMSUNG_REGS_AC97_H__ +#define __SAMSUNG_REGS_AC97_H__ + +#define S3C_AC97_GLBCTRL (0x00) + +#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22) +#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21) +#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20) +#define S3C_AC97_GLBCTRL_MICINORIE (1<<19) +#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18) +#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17) +#define S3C_AC97_GLBCTRL_MICINTIE (1<<16) +#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12) +#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12) +#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12) +#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12) +#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10) +#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10) +#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10) +#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10) +#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8) +#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8) +#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8) +#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8) +#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3) +#define S3C_AC97_GLBCTRL_ACLINKON (1<<2) +#define S3C_AC97_GLBCTRL_WARMRESET (1<<1) +#define S3C_AC97_GLBCTRL_COLDRESET (1<<0) + +#define S3C_AC97_GLBSTAT (0x04) + +#define S3C_AC97_GLBSTAT_CODECREADY (1<<22) +#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21) +#define S3C_AC97_GLBSTAT_PCMINORI (1<<20) +#define S3C_AC97_GLBSTAT_MICINORI (1<<19) +#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18) +#define S3C_AC97_GLBSTAT_PCMINTI (1<<17) +#define S3C_AC97_GLBSTAT_MICINTI (1<<16) +#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0) +#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0) +#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0) +#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0) +#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0) +#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0) + +#define S3C_AC97_CODEC_CMD (0x08) + +#define S3C_AC97_CODEC_CMD_READ (1<<23) + +#define S3C_AC97_STAT (0x0c) +#define S3C_AC97_PCM_ADDR (0x10) +#define S3C_AC97_PCM_DATA (0x18) +#define S3C_AC97_MIC_DATA (0x1C) + +#endif /* __SAMSUNG_REGS_AC97_H__ */ diff --git a/sound/soc/samsung/regs-iis.h b/sound/soc/samsung/regs-iis.h new file mode 100644 index 00000000000..dc6cbbe9c4f --- /dev/null +++ b/sound/soc/samsung/regs-iis.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + * + * 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. + * + * S3C2410 IIS register definition +*/ + +#ifndef __SAMSUNG_REGS_IIS_H__ +#define __SAMSUNG_REGS_IIS_H__ + +#define S3C2410_IISCON (0x00) + +#define S3C2410_IISCON_LRINDEX (1 << 8) +#define S3C2410_IISCON_TXFIFORDY (1 << 7) +#define S3C2410_IISCON_RXFIFORDY (1 << 6) +#define S3C2410_IISCON_TXDMAEN (1 << 5) +#define S3C2410_IISCON_RXDMAEN (1 << 4) +#define S3C2410_IISCON_TXIDLE (1 << 3) +#define S3C2410_IISCON_RXIDLE (1 << 2) +#define S3C2410_IISCON_PSCEN (1 << 1) +#define S3C2410_IISCON_IISEN (1 << 0) + +#define S3C2410_IISMOD (0x04) + +#define S3C2440_IISMOD_MPLL (1 << 9) +#define S3C2410_IISMOD_SLAVE (1 << 8) +#define S3C2410_IISMOD_NOXFER (0 << 6) +#define S3C2410_IISMOD_RXMODE (1 << 6) +#define S3C2410_IISMOD_TXMODE (2 << 6) +#define S3C2410_IISMOD_TXRXMODE (3 << 6) +#define S3C2410_IISMOD_LR_LLOW (0 << 5) +#define S3C2410_IISMOD_LR_RLOW (1 << 5) +#define S3C2410_IISMOD_IIS (0 << 4) +#define S3C2410_IISMOD_MSB (1 << 4) +#define S3C2410_IISMOD_8BIT (0 << 3) +#define S3C2410_IISMOD_16BIT (1 << 3) +#define S3C2410_IISMOD_BITMASK (1 << 3) +#define S3C2410_IISMOD_256FS (0 << 2) +#define S3C2410_IISMOD_384FS (1 << 2) +#define S3C2410_IISMOD_16FS (0 << 0) +#define S3C2410_IISMOD_32FS (1 << 0) +#define S3C2410_IISMOD_48FS (2 << 0) +#define S3C2410_IISMOD_FS_MASK (3 << 0) + +#define S3C2410_IISPSR (0x08) + +#define S3C2410_IISPSR_INTMASK (31 << 5) +#define S3C2410_IISPSR_INTSHIFT (5) +#define S3C2410_IISPSR_EXTMASK (31 << 0) +#define S3C2410_IISPSR_EXTSHFIT (0) + +#define S3C2410_IISFCON (0x0c) + +#define S3C2410_IISFCON_TXDMA (1 << 15) +#define S3C2410_IISFCON_RXDMA (1 << 14) +#define S3C2410_IISFCON_TXENABLE (1 << 13) +#define S3C2410_IISFCON_RXENABLE (1 << 12) +#define S3C2410_IISFCON_TXMASK (0x3f << 6) +#define S3C2410_IISFCON_TXSHIFT (6) +#define S3C2410_IISFCON_RXMASK (0x3f) +#define S3C2410_IISFCON_RXSHIFT (0) + +#define S3C2410_IISFIFO (0x10) + +#endif /* __SAMSUNG_REGS_IIS_H__ */ diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 21e12361a9c..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 <plat/regs-iis.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); @@ -85,7 +87,7 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = { .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "uda1380-hifi", .init = rx1950_uda1380_init, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .codec_name = "uda1380-codec.0-001a", .ops = &rx1950_ops, }, @@ -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 7a73380b356..0ff4bbe23af 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -1,6 +1,4 @@ -/* sound/soc/samsung/s3c-i2c-v2.c - * - * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. +/* ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. * * Copyright (c) 2006 Wolfson Microelectronics PLC. * Graeme Gregory graeme.gregory@wolfsonmicro.com @@ -33,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 @@ -328,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; } @@ -731,10 +725,11 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #define s3c2412_i2s_resume NULL #endif -int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv) +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) @@ -747,11 +742,11 @@ int s3c_i2sv2_register_dai(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_dai(dev, drv); + return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1); } -EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); +EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index f8297d9bb8a..90abab364b4 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, unsigned long base); /** - * s3c_i2sv2_register_dai - register dai with soc core + * s3c_i2sv2_register_component - register component and dai with soc core * @dev: DAI device * @id: DAI ID * @drv: The driver structure to register @@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * Fill in any missing fields and then register the given dai with the * soc core. */ -extern int s3c_i2sv2_register_dai(struct device *dev, int id, - struct snd_soc_dai_driver *drv); +extern int s3c_i2sv2_register_component(struct device *dev, int id, + struct snd_soc_component_driver *cmp_drv, + struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 79fbeea99d4..08c059be910 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -25,18 +25,19 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/regs-gpio.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" }; @@ -83,12 +84,9 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; - /* Configure the I2S pins in correct mode */ - s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); - s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); - s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); return 0; } @@ -122,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; } @@ -164,20 +162,31 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = { .ops = &s3c2412_i2s_dai_ops, }; -static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev) -{ - return s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai); -} +static const struct snd_soc_component_driver s3c2412_i2s_component = { + .name = "s3c2412-i2s", +}; -static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev) +static int s3c2412_iis_dev_probe(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); - return 0; + int ret = 0; + + ret = s3c_i2sv2_register_component(&pdev->dev, -1, + &s3c2412_i2s_component, + &s3c2412_i2s_dai); + if (ret) { + pr_err("failed to register the dai\n"); + return ret; + } + + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) + pr_err("failed to register the DMA: %d\n", ret); + + return ret; } static struct platform_driver s3c2412_iis_driver = { .probe = s3c2412_iis_dev_probe, - .remove = __devexit_p(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 c4aa4d412fb..9aba9fb7df0 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -23,18 +23,19 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/regs-gpio.h> #include <mach/dma.h> -#include <plat/regs-iis.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" }; @@ -247,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; @@ -391,12 +392,9 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) } clk_enable(s3c24xx_i2s.iis_clk); - /* Configure the I2S pins in correct mode */ - s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); - s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); - s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); @@ -469,20 +467,30 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = { .ops = &s3c24xx_i2s_dai_ops, }; -static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev) -{ - return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai); -} +static const struct snd_soc_component_driver s3c24xx_i2s_component = { + .name = "s3c24xx-i2s", +}; -static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev) +static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); - return 0; + int ret = 0; + + 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 = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) + pr_err("failed to register the dma: %d\n", ret); + + return ret; } static struct platform_driver s3c24xx_iis_driver = { .probe = s3c24xx_iis_dev_probe, - .remove = __devexit_p(s3c24xx_iis_dev_remove), .driver = { .name = "s3c24xx-iis", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index 656d5afe4ca..2c015f62ead 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c @@ -13,7 +13,7 @@ #include <sound/soc.h> -#include <plat/audio-simtec.h> +#include <linux/platform_data/asoc-s3c24xx_simtec.h> #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" @@ -313,8 +313,8 @@ const struct dev_pm_ops simtec_audio_pmops = { EXPORT_SYMBOL_GPL(simtec_audio_pmops); #endif -int __devinit simtec_audio_core_probe(struct platform_device *pdev, - struct snd_soc_card *card) +int simtec_audio_core_probe(struct platform_device *pdev, + struct snd_soc_card *card) { struct platform_device *snd_dev; int ret; @@ -371,7 +371,7 @@ err_clk: } EXPORT_SYMBOL_GPL(simtec_audio_core_probe); -int __devexit simtec_audio_remove(struct platform_device *pdev) +int simtec_audio_remove(struct platform_device *pdev) { struct platform_device *snd_dev = platform_get_drvdata(pdev); diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index 7ace6a87f41..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; @@ -82,7 +74,7 @@ static struct snd_soc_dai_link simtec_dai_aic33 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_hermes_init, }; @@ -99,7 +91,7 @@ static struct snd_soc_card snd_soc_machine_simtec_aic33 = { .num_dapm_routes = ARRAY_SIZE(base_map), }; -static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) +static int simtec_audio_hermes_probe(struct platform_device *pd) { dev_info(&pd->dev, "probing....\n"); return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33); @@ -112,7 +104,7 @@ static struct platform_driver simtec_audio_hermes_platdrv = { .pm = simtec_audio_pm, }, .probe = simtec_audio_hermes_probe, - .remove = __devexit_p(simtec_audio_remove), + .remove = simtec_audio_remove, }; module_platform_driver(simtec_audio_hermes_platdrv); diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index c42d5f00b0e..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; @@ -71,7 +63,7 @@ static struct snd_soc_dai_link simtec_dai_aic23 = { .codec_name = "tlv320aic3x-codec.0-001a", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", .init = simtec_tlv320aic23_init, }; @@ -88,7 +80,7 @@ static struct snd_soc_card snd_soc_machine_simtec_aic23 = { .num_dapm_routes = ARRAY_SIZE(base_map), }; -static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) +static int simtec_audio_tlv320aic23_probe(struct platform_device *pd) { return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23); } @@ -100,7 +92,7 @@ static struct platform_driver simtec_audio_tlv320aic23_driver = { .pm = simtec_audio_pm, }, .probe = simtec_audio_tlv320aic23_probe, - .remove = __devexit_p(simtec_audio_remove), + .remove = simtec_audio_remove, }; module_platform_driver(simtec_audio_tlv320aic23_driver); diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index d731042e51b..1b7b52b0af9 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -18,7 +18,7 @@ #include <sound/soc.h> #include <sound/s3c24xx_uda134x.h> -#include <plat/regs-iis.h> +#include "regs-iis.h" #include "s3c24xx-i2s.h" @@ -224,7 +224,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .codec_dai_name = "uda134x-hifi", .cpu_dai_name = "s3c24xx-iis", .ops = &s3c24xx_uda134x_ops, - .platform_name = "samsung-audio", + .platform_name = "s3c24xx-iis", }; static struct snd_soc_card snd_soc_s3c24xx_uda134x = { diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index f2dcb424ea2..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,13 +182,21 @@ 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", .stream_name = "SmartQ Hi-Fi", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8750-hifi", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8750.0-0x1a", .init = smartq_wm8987_init, .ops = &smartq_hifi_ops, @@ -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/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c index 720ba29bb7e..c390aad68cf 100644 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ b/sound/soc/samsung/smdk2443_wm9710.c @@ -24,7 +24,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = { .cpu_dai_name = "samsung-ac97", .codec_dai_name = "ac97-hifi", .codec_name = "ac97-codec", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", }, }; diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index beaa9c15d69..a2f2363fe1c 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c @@ -151,7 +151,7 @@ static struct snd_soc_ops smdk_spdif_ops = { static struct snd_soc_dai_link smdk_dai = { .name = "S/PDIF", .stream_name = "S/PDIF PCM Playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-spdif", .cpu_dai_name = "samsung-spdif", .codec_dai_name = "dit-hifi", .codec_name = "spdif-dit", diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index ade2809cf39..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: @@ -176,7 +174,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Playback", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, @@ -185,7 +183,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, @@ -193,9 +191,9 @@ static struct snd_soc_dai_link smdk_dai[] = { [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ .name = "Sec_FIFO TX", .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s.x", + .cpu_dai_name = "samsung-i2s-sec", .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s-sec", .codec_name = "wm8580.0-001b", .ops = &smdk_ops, }, @@ -223,9 +221,6 @@ static int __init smdk_audio_init(void) if (machine_is_smdkc100() || machine_is_smdkv210() || machine_is_smdkc110()) { smdk.num_links = 3; - /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ - str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; - str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; } else if (machine_is_smdk6410()) { str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; str[strlen(str) - 1] = '2'; diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c index fab5322e9f0..e119aaa91c2 100644 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ b/sound/soc/samsung/smdk_wm8580pcm.c @@ -135,7 +135,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Capture", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8580.0-001b", .ops = &smdk_wm8580_pcm_ops, }, @@ -153,7 +153,7 @@ static struct snd_soc_card smdk_pcm = { * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), * 2.0484Mhz, directly with MCLK both Codec and SoC. */ -static int __devinit snd_smdk_probe(struct platform_device *pdev) +static int snd_smdk_probe(struct platform_device *pdev) { int ret = 0; @@ -164,20 +164,11 @@ static int __devinit 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 __devexit snd_smdk_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&smdk_pcm); - platform_set_drvdata(pdev, NULL); - return 0; + return ret; } static struct platform_driver snd_smdk_driver = { @@ -186,7 +177,6 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = __devexit_p(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 8eb309f23d1..3d6272a8cad 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -9,7 +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: @@ -36,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) @@ -90,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"); @@ -127,17 +114,21 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Pri_Dai", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .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", .stream_name = "Sec_Dai", - .cpu_dai_name = "samsung-i2s.4", + .cpu_dai_name = "samsung-i2s-sec", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .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, }, }; @@ -149,31 +140,66 @@ static struct snd_soc_card smdk = { .num_links = ARRAY_SIZE(smdk_dai), }; -static struct platform_device *smdk_snd_device; +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 __init smdk_audio_init(void) +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; - smdk_snd_device = platform_device_alloc("soc-audio", -1); - if (!smdk_snd_device) + board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL); + if (!board) return -ENOMEM; - platform_set_drvdata(smdk_snd_device, &smdk); + if (np) { + smdk_dai[0].cpu_dai_name = NULL; + smdk_dai[0].cpu_of_node = of_parse_phandle(np, + "samsung,i2s-controller", 0); + if (!smdk_dai[0].cpu_of_node) { + dev_err(&pdev->dev, + "Property 'samsung,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + } + + smdk_dai[0].platform_name = NULL; + smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; + } + + 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); - ret = platform_device_add(smdk_snd_device); if (ret) - platform_device_put(smdk_snd_device); + dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); return ret; } -module_init(smdk_audio_init); -static void __exit smdk_audio_exit(void) -{ - platform_device_unregister(smdk_snd_device); -} -module_exit(smdk_audio_exit); +static struct platform_driver smdk_audio_driver = { + .driver = { + .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, +}; + +module_platform_driver(smdk_audio_driver); MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:smdk-audio-wm8994"); diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 77ecba93511..b6c09979be1 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -116,7 +116,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Primary PCM", .cpu_dai_name = "samsung-pcm.0", .codec_dai_name = "wm8994-aif1", - .platform_name = "samsung-audio", + .platform_name = "samsung-pcm.0", .codec_name = "wm8994-codec", .ops = &smdk_wm8994_pcm_ops, }, @@ -129,25 +129,16 @@ static struct snd_soc_card smdk_pcm = { .num_links = 1, }; -static int __devinit snd_smdk_probe(struct platform_device *pdev) +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 __devexit snd_smdk_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&smdk_pcm); - platform_set_drvdata(pdev, NULL); - return 0; + return ret; } static struct platform_driver snd_smdk_driver = { @@ -156,7 +147,6 @@ static struct platform_driver snd_smdk_driver = { .name = "samsung-smdk-pcm", }, .probe = snd_smdk_probe, - .remove = __devexit_p(snd_smdk_remove), }; module_platform_driver(snd_smdk_driver); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c index 55b2ca7f329..0d20e4ed27a 100644 --- a/sound/soc/samsung/smdk_wm9713.c +++ b/sound/soc/samsung/smdk_wm9713.c @@ -42,7 +42,7 @@ static struct snd_soc_card smdk; static struct snd_soc_dai_link smdk_dai = { .name = "AC97", .stream_name = "AC97 PCM", - .platform_name = "samsung-audio", + .platform_name = "samsung-ac97", .cpu_dai_name = "samsung-ac97", .codec_dai_name = "wm9713-hifi", .codec_name = "wm9713-codec", 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 a5a56a12034..d9ffc48fce5 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -17,8 +17,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <plat/audio.h> -#include <mach/dma.h> +#include <linux/platform_data/asoc-s3c.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: @@ -357,7 +356,11 @@ static struct snd_soc_dai_driver samsung_spdif_dai = { .resume = spdif_resume, }; -static __devinit int spdif_probe(struct platform_device *pdev) +static const struct snd_soc_component_driver samsung_spdif_component = { + .name = "samsung-spdif", +}; + +static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; struct resource *mem_res, *dma_res; @@ -391,21 +394,21 @@ static __devinit 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; goto err0; } - clk_enable(spdif->pclk); + 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; goto err1; } - clk_enable(spdif->sclk); + clk_prepare_enable(spdif->sclk); /* Request S/PDIF Register's memory region */ if (!request_mem_region(mem_res->start, @@ -424,7 +427,8 @@ static __devinit int spdif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, spdif); - ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai); + 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; @@ -437,46 +441,45 @@ static __devinit int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; - return 0; + ret = samsung_asoc_dma_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); + goto err4; + } + return 0; err4: iounmap(spdif->regs); err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: - clk_disable(spdif->sclk); - clk_put(spdif->sclk); + clk_disable_unprepare(spdif->sclk); err1: - clk_disable(spdif->pclk); - clk_put(spdif->pclk); + clk_disable_unprepare(spdif->pclk); err0: return ret; } -static __devexit int spdif_remove(struct platform_device *pdev) +static int spdif_remove(struct platform_device *pdev) { struct samsung_spdif_info *spdif = &spdif_info; struct resource *mem_res; - snd_soc_unregister_dai(&pdev->dev); - iounmap(spdif->regs); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (mem_res) release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable(spdif->sclk); - clk_put(spdif->sclk); - clk_disable(spdif->pclk); - clk_put(spdif->pclk); + clk_disable_unprepare(spdif->sclk); + clk_disable_unprepare(spdif->pclk); return 0; } static struct platform_driver samsung_spdif_driver = { .probe = spdif_probe, - .remove = __devexit_p(spdif_remove), + .remove = spdif_remove, .driver = { .name = "samsung-spdif", .owner = THIS_MODULE, diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index a4a9fc7e8c7..9902efcb8ea 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -25,7 +25,7 @@ static int speyside_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; int ret; if (dapm->dev != codec_dai->dev) @@ -57,7 +57,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; int ret; if (dapm->dev != codec_dai->dev) @@ -126,6 +126,18 @@ static void speyside_set_polarity(struct snd_soc_codec *codec, snd_soc_dapm_sync(&codec->dapm); } +static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(dai, 0, MCLK_AUDIO_RATE, 0); + if (ret < 0) + return ret; + + return 0; +} + static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->codec_dai; @@ -172,17 +184,37 @@ static int speyside_late_probe(struct snd_soc_card *card) return 0; } +static const struct snd_soc_pcm_stream dsp_codec_params = { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + static struct snd_soc_dai_link speyside_dai[] = { { - .name = "CPU", - .stream_name = "CPU", + .name = "CPU-DSP", + .stream_name = "CPU-DSP", .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "wm0010-sdi1", + .platform_name = "samsung-i2s.0", + .codec_name = "spi0.0", + .init = speyside_wm0010_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + }, + { + .name = "DSP-CODEC", + .stream_name = "DSP-CODEC", + .cpu_dai_name = "wm0010-sdi2", .codec_dai_name = "wm8996-aif1", - .platform_name = "samsung-audio", .codec_name = "wm8996.1-001a", .init = speyside_wm8996_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, + .params = &dsp_codec_params, + .ignore_suspend = 1, }, { .name = "Baseband", @@ -288,30 +320,19 @@ static struct snd_soc_card speyside = { .late_probe = speyside_late_probe, }; -static __devinit int speyside_probe(struct platform_device *pdev) +static int speyside_probe(struct platform_device *pdev) { struct snd_soc_card *card = &speyside; int ret; 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 __devexit 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 = { @@ -321,7 +342,6 @@ static struct platform_driver speyside_driver = { .pm = &snd_soc_pm_ops, }, .probe = speyside_probe, - .remove = __devexit_p(speyside_remove), }; module_platform_driver(speyside_driver); diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 9199649bf78..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; } } @@ -110,7 +112,7 @@ static struct snd_soc_dai_link tobermory_dai[] = { .stream_name = "CPU", .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8962", - .platform_name = "samsung-audio", + .platform_name = "samsung-i2s.0", .codec_name = "wm8962.1-001a", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, @@ -214,30 +216,19 @@ static struct snd_soc_card tobermory = { .late_probe = tobermory_late_probe, }; -static __devinit int tobermory_probe(struct platform_device *pdev) +static int tobermory_probe(struct platform_device *pdev) { struct snd_soc_card *card = &tobermory; int ret; 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 __devexit 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 = __devexit_p(tobermory_remove), }; module_platform_driver(tobermory_driver); |
