aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/s3c24xx
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/s3c24xx')
-rw-r--r--sound/soc/s3c24xx/Kconfig37
-rw-r--r--sound/soc/s3c24xx/Makefile10
-rw-r--r--sound/soc/s3c24xx/aquila_wm8994.c295
-rw-r--r--sound/soc/s3c24xx/goni_wm8994.c298
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c23
-rw-r--r--sound/soc/s3c24xx/ln2440sbc_alc650.c17
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c58
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c37
-rw-r--r--sound/soc/s3c24xx/rx1950_uda1380.c333
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c36
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.h2
-rw-r--r--sound/soc/s3c24xx/s3c-dma.c46
-rw-r--r--sound/soc/s3c24xx/s3c-dma.h1
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c50
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h13
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.c54
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.h3
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c54
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h2
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c40
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.h2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.c15
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.h4
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_hermes.c25
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c21
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c21
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s-v4.c135
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c206
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h3
-rw-r--r--sound/soc/s3c24xx/smartq_wm8987.c15
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c17
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c68
-rw-r--r--sound/soc/s3c24xx/smdk_spdif.c223
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c42
-rw-r--r--sound/soc/s3c24xx/spdif.c501
-rw-r--r--sound/soc/s3c24xx/spdif.h19
36 files changed, 2260 insertions, 466 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 213963ac3c28..8a6b53ccd203 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -36,6 +36,10 @@ config SND_S3C_SOC_AC97
tristate
select SND_SOC_AC97_BUS
+config SND_S5P_SOC_SPDIF
+ tristate
+ select SND_SOC_SPDIF
+
config SND_S3C24XX_SOC_NEO1973_WM8753
tristate "SoC I2S Audio support for NEO1973 - WM8753"
depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -118,6 +122,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
select SND_SOC_TLV320AIC3X
select SND_S3C24XX_SOC_SIMTEC
+config SND_S3C24XX_SOC_RX1950_UDA1380
+ tristate "Audio support for the HP iPAQ RX1950"
+ depends on SND_S3C24XX_SOC && MACH_RX1950
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_UDA1380
+ help
+ This driver provides audio support for HP iPAQ RX1950 PDA.
+
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
@@ -131,3 +143,28 @@ config SND_S3C64XX_SOC_SMARTQ
depends on SND_S3C24XX_SOC && MACH_SMARTQ
select SND_S3C64XX_SOC_I2S
select SND_SOC_WM8750
+
+config SND_S5PC110_SOC_AQUILA_WM8994
+ tristate "SoC I2S Audio support for AQUILA - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_AQUILA
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on aquila
+ with the WM8994.
+
+config SND_S5PV210_SOC_GONI_WM8994
+ tristate "SoC I2S Audio support for GONI - WM8994"
+ depends on SND_S3C24XX_SOC && MACH_GONI
+ select SND_S3C64XX_SOC_I2S_V4
+ select SND_SOC_WM8994
+ help
+ Say Y if you want to add support for SoC audio on goni
+ with the WM8994.
+
+config SND_SOC_SMDK_SPDIF
+ tristate "SoC S/PDIF Audio support for SMDK"
+ depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+ select SND_S5P_SOC_SPDIF
+ help
+ Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 50172c385d90..ee8f41d6df99 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -7,6 +7,7 @@ snd-soc-s3c-ac97-objs := s3c-ac97.o
snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-s3c-pcm-objs := s3c-pcm.o
+snd-soc-samsung-spdif-objs := spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
+obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -27,9 +29,13 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-aquila-wm8994-objs := aquila_wm8994.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -40,6 +46,10 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
+obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
new file mode 100644
index 000000000000..235d1973f7d0
--- /dev/null
+++ b/sound/soc/s3c24xx/aquila_wm8994.c
@@ -0,0 +1,295 @@
+/*
+ * aquila_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card aquila;
+static struct platform_device *aquila_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
+ {"Ext Spk", NULL, "SPKOUTLP"},
+ {"Ext Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add aquila specific widgets */
+ snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
+ ARRAY_SIZE(aquila_dapm_widgets));
+
+ /* set up aquila specific audio routes */
+ snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
+ ARRAY_SIZE(aquila_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
+ snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&aquila, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int aquila_hifi_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 *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ 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;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ 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;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops aquila_hifi_ops = {
+ .hw_params = aquila_hifi_hw_params,
+};
+
+static int aquila_voice_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 *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "aquila-voice-dai",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops aquila_voice_ops = {
+ .hw_params = aquila_voice_hw_params,
+};
+
+static struct snd_soc_dai_link aquila_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = aquila_wm8994_init,
+ .ops = &aquila_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "aquila-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &aquila_voice_ops,
+},
+};
+
+static struct snd_soc_card aquila = {
+ .name = "aquila",
+ .dai_link = aquila_dai,
+ .num_links = ARRAY_SIZE(aquila_dai),
+};
+
+static int __init aquila_init(void)
+{
+ int ret;
+
+ if (!machine_is_aquila())
+ return -ENODEV;
+
+ aquila_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!aquila_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(aquila_snd_device, &aquila);
+ ret = platform_device_add(aquila_snd_device);
+
+ if (ret)
+ platform_device_put(aquila_snd_device);
+
+ return ret;
+}
+
+static void __exit aquila_exit(void)
+{
+ platform_device_unregister(aquila_snd_device);
+}
+
+module_init(aquila_init);
+module_exit(aquila_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
new file mode 100644
index 000000000000..694f702cc8e2
--- /dev/null
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -0,0 +1,298 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ }, {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+ {
+ .gpio = S5PV210_GPH0(6),
+ .name = "DET_3.5",
+ .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_AVOUT,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_MIC("2nd Mic", NULL),
+ SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+ {"Ext Left Spk", NULL, "SPKOUTLP"},
+ {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+ {"Ext Right Spk", NULL, "SPKOUTRP"},
+ {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+ {"Ext Rcv", NULL, "HPOUT2N"},
+ {"Ext Rcv", NULL, "HPOUT2P"},
+
+ {"Headset Stereophone", NULL, "HPOUT1L"},
+ {"Headset Stereophone", NULL, "HPOUT1R"},
+
+ {"IN1RN", NULL, "Headset Mic"},
+ {"IN1RP", NULL, "Headset Mic"},
+
+ {"IN1RN", NULL, "2nd Mic"},
+ {"IN1RP", NULL, "2nd Mic"},
+
+ {"IN1LN", NULL, "Main Mic"},
+ {"IN1LP", NULL, "Main Mic"},
+
+ {"IN2LN", NULL, "Radio In"},
+ {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret;
+
+ /* add goni specific widgets */
+ snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
+ ARRAY_SIZE(goni_dapm_widgets));
+
+ /* set up goni specific audio routes */
+ snd_soc_dapm_add_routes(codec, goni_dapm_routes,
+ ARRAY_SIZE(goni_dapm_routes));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
+ snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
+ snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
+
+ snd_soc_dapm_sync(codec);
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&goni, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+ &jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int goni_hifi_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 *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ /* set the cpu DAI configuration */
+ 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;
+
+ /* set the cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec DAI configuration */
+ 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;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+ .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_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 *codec_dai = rtd->codec_dai;
+ unsigned int pll_out = 24000000;
+ int ret = 0;
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec FLL */
+ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+ params_rate(params) * 256);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+ params_rate(params) * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+ .name = "goni-voice-dai",
+ .id = 0,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+ .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+ .name = "WM8994",
+ .stream_name = "WM8994 HiFi",
+ .cpu_dai_name = "s3c64xx-i2s-v4",
+ .codec_dai_name = "wm8994-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .init = goni_wm8994_init,
+ .ops = &goni_hifi_ops,
+}, {
+ .name = "WM8994 Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "goni-voice-dai",
+ .codec_dai_name = "wm8994-voice",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8994-codec.0-0x1a",
+ .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+ .name = "goni",
+ .dai_link = goni_dai,
+ .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+ int ret;
+
+ if (!machine_is_goni())
+ return -ENODEV;
+
+ goni_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!goni_snd_device)
+ return -ENOMEM;
+
+ /* register voice DAI here */
+ ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(goni_snd_device, &goni);
+ ret = platform_device_add(goni_snd_device);
+
+ if (ret)
+ platform_device_put(goni_snd_device);
+
+ return ret;
+}
+
+static void __exit goni_exit(void)
+{
+ platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 8c108b121c10..49605cd83947 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -49,8 +49,8 @@ static int jive_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 *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_i2sv2_rate_calc div;
unsigned int clk = 0;
int ret = 0;
@@ -108,8 +108,9 @@ static struct snd_soc_ops jive_ops = {
.hw_params = jive_hw_params,
};
-static int jive_wm8750_init(struct snd_soc_codec *codec)
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* These endpoints are not being used. */
@@ -138,8 +139,10 @@ static int jive_wm8750_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link jive_dai = {
.name = "wm8750",
.stream_name = "WM8750",
- .cpu_dai = &s3c2412_i2s_dai,
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c2412-i2s",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = jive_wm8750_init,
.ops = &jive_ops,
};
@@ -147,17 +150,10 @@ static struct snd_soc_dai_link jive_dai = {
/* jive audio machine driver */
static struct snd_soc_card snd_soc_machine_jive = {
.name = "Jive",
- .platform = &s3c24xx_soc_platform,
.dai_link = &jive_dai,
.num_links = 1,
};
-/* jive audio subsystem */
-static struct snd_soc_device jive_snd_devdata = {
- .card = &snd_soc_machine_jive,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *jive_snd_device;
static int __init jive_init(void)
@@ -173,8 +169,7 @@ static int __init jive_init(void)
if (!jive_snd_device)
return -ENOMEM;
- platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
- jive_snd_devdata.dev = &jive_snd_device->dev;
+ platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
ret = platform_device_add(jive_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index ffa954fe6931..abe64abe8c84 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -23,7 +23,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -33,23 +32,19 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card ln2440sbc = {
.name = "LN2440SBC",
- .platform = &s3c24xx_soc_platform,
.dai_link = ln2440sbc_dai,
.num_links = ARRAY_SIZE(ln2440sbc_dai),
};
-static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
- .card = &ln2440sbc,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *ln2440sbc_snd_ac97_device;
static int __init ln2440sbc_init(void)
@@ -60,9 +55,7 @@ static int __init ln2440sbc_init(void)
if (!ln2440sbc_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(ln2440sbc_snd_ac97_device,
- &ln2440sbc_snd_ac97_devdata);
- ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+ platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
ret = platform_device_add(ln2440sbc_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 4719558289d4..e97bdf150a03 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -41,8 +41,8 @@ static int neo1973_gta02_hifi_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 *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -130,7 +130,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
@@ -149,7 +149,7 @@ static int neo1973_gta02_voice_hw_params(
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -194,7 +194,7 @@ static int neo1973_gta02_voice_hw_params(
static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
@@ -262,7 +262,7 @@ 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(value));
+ gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
return 0;
}
@@ -330,8 +330,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
* This is an example machine initialisation for a wm8753 connected to a
* neo1973 GTA02.
*/
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
/* set up NC codec pins */
@@ -378,9 +379,8 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
/*
* BT Codec DAI
*/
-static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+static struct snd_soc_dai_driver bt_dai = {
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -397,32 +397,30 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
.init = neo1973_gta02_wm8753_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_gta02_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
.ops = &neo1973_gta02_voice_ops,
+ .codec_name = "wm8753-codec.0-0x1a",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card neo1973_gta02 = {
.name = "neo1973-gta02",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_gta02_dai,
.num_links = ARRAY_SIZE(neo1973_gta02_dai),
};
-static struct snd_soc_device neo1973_gta02_snd_devdata = {
- .card = &neo1973_gta02,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static struct platform_device *neo1973_gta02_snd_device;
static int __init neo1973_gta02_init(void)
@@ -435,18 +433,18 @@ static int __init neo1973_gta02_init(void)
return -ENODEV;
}
- /* register bluetooth DAI here */
- ret = snd_soc_register_dai(&bt_dai);
- if (ret)
- return ret;
-
neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
if (!neo1973_gta02_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_gta02_snd_device,
- &neo1973_gta02_snd_devdata);
- neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
+ /* register bluetooth DAI here */
+ ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
+ if (ret) {
+ platform_device_put(neo1973_gta02_snd_device);
+ return ret;
+ }
+
+ platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
ret = platform_device_add(neo1973_gta02_snd_device);
if (ret) {
@@ -461,7 +459,7 @@ static int __init neo1973_gta02_init(void)
goto err_unregister_device;
}
- ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
+ ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
if (ret) {
pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
goto err_free_gpio_hp_in;
@@ -493,7 +491,7 @@ module_init(neo1973_gta02_init);
static void __exit neo1973_gta02_exit(void)
{
- snd_soc_unregister_dai(&bt_dai);
+ snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
platform_device_unregister(neo1973_gta02_snd_device);
gpio_free(GTA02_GPIO_HP_IN);
gpio_free(GTA02_GPIO_AMP_SHUT);
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 4ac620988e7c..f4f2ee731f01 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -57,8 +57,8 @@ static int neo1973_hifi_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 *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0, bclk = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -147,7 +147,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -167,7 +167,7 @@ static int neo1973_voice_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 *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pcmdiv = 0;
int ret = 0;
unsigned long iis_clkrate;
@@ -213,7 +213,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
pr_debug("Entered %s\n", __func__);
@@ -499,8 +499,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
* neo1973 II. It is missing logic to detect hp/mic insertions and logic
* to re-route the audio in such an event.
*/
-static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
int err;
pr_debug("Entered %s\n", __func__);
@@ -538,8 +539,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
* BT Codec DAI
*/
static struct snd_soc_dai bt_dai = {
- .name = "Bluetooth",
- .id = 0,
+ .name = "bluetooth-dai",
.playback = {
.channels_min = 1,
.channels_max = 1,
@@ -556,32 +556,30 @@ static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
.stream_name = "WM8753 HiFi",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "wm8753-hifi",
+ .codec_name = "wm8753-codec.0-0x1a",
.init = neo1973_wm8753_init,
.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
.name = "Bluetooth",
.stream_name = "Voice",
- .cpu_dai = &bt_dai,
- .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "bluetooth-dai",
+ .codec_dai_name = "wm8753-voice",
+ .codec_name = "wm8753-codec.0-0x1a",
.ops = &neo1973_voice_ops,
},
};
static struct snd_soc_card neo1973 = {
.name = "neo1973",
- .platform = &s3c24xx_soc_platform,
.dai_link = neo1973_dai,
.num_links = ARRAY_SIZE(neo1973_dai),
};
-static struct snd_soc_device neo1973_snd_devdata = {
- .card = &neo1973,
- .codec_dev = &soc_codec_dev_wm8753,
-};
-
static int lm4857_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -673,8 +671,7 @@ static int __init neo1973_init(void)
if (!neo1973_snd_device)
return -ENOMEM;
- platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
- neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+ platform_set_drvdata(neo1973_snd_device, &neo1973);
ret = platform_device_add(neo1973_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
new file mode 100644
index 000000000000..ffd5cf2fb0a9
--- /dev/null
+++ b/sound/soc/s3c24xx/rx1950_uda1380.c
@@ -0,0 +1,333 @@
+/*
+ * rx1950.c -- ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
+ * Philipp Zabel <philipp.zabel@gmail.com>
+ * Denis Grigoriev <dgreenday@gmail.com>
+ * Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+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);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+ 16000,
+ 44100,
+ 48000,
+ 88200,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1,
+ },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+ [0] = {
+ .gpio = S3C2410_GPG(12),
+ .name = "hp-gpio",
+ .report = SND_JACK_HEADPHONE,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+ .startup = rx1950_startup,
+ .hw_params = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+ {
+ .name = "uda1380",
+ .stream_name = "UDA1380 Duplex",
+ .cpu_dai_name = "s3c24xx-iis",
+ .codec_dai_name = "uda1380-hifi",
+ .init = rx1950_uda1380_init,
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "uda1380-codec.0-001a",
+ .ops = &rx1950_ops,
+ },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+ .name = "rx1950",
+ .dai_link = rx1950_uda1380_dai,
+ .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* headphone connected to VOUTLHP, VOUTRHP */
+ {"Headphone Jack", NULL, "VOUTLHP"},
+ {"Headphone Jack", NULL, "VOUTRHP"},
+
+ /* ext speaker connected to VOUTL, VOUTR */
+ {"Speaker", NULL, "VOUTL"},
+ {"Speaker", NULL, "VOUTR"},
+
+ /* mic is connected to VINM */
+ {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+static struct clk *xtal;
+
+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);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpio_set_value(S3C2410_GPA(1), 1);
+ else
+ gpio_set_value(S3C2410_GPA(1), 0);
+
+ return 0;
+}
+
+static int rx1950_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;
+ int div;
+ int ret;
+ unsigned int rate = params_rate(params);
+ int clk_source, fs_mode;
+
+ switch (rate) {
+ case 16000:
+ case 48000:
+ clk_source = S3C24XX_CLKSRC_PCLK;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+ if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ case 44100:
+ case 88200:
+ clk_source = S3C24XX_CLKSRC_MPLL;
+ fs_mode = S3C2410_IISMOD_256FS;
+ div = clk_get_rate(xtal) / (256 * rate);
+ if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+ div++;
+ break;
+ default:
+ printk(KERN_ERR "%s: rate %d is not supported\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* select clock source */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_384FS);
+ if (ret < 0)
+ return ret;
+
+ /* set BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+ S3C2410_IISMOD_32FS);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(div, div));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int err;
+
+ /* Add rx1950 specific widgets */
+ err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+ ARRAY_SIZE(uda1380_dapm_widgets));
+
+ if (err)
+ return err;
+
+ /* Set up rx1950 specific audio path audio_mapnects */
+ err = snd_soc_dapm_add_routes(codec, audio_map,
+ ARRAY_SIZE(audio_map));
+
+ if (err)
+ return err;
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Speaker");
+
+ snd_soc_dapm_sync(codec);
+
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &hp_jack);
+
+ snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+ hp_jack_pins);
+
+ snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+ hp_jack_gpios);
+
+ return 0;
+}
+
+static int __init rx1950_init(void)
+{
+ int ret;
+
+ if (!machine_is_rx1950())
+ return -ENODEV;
+
+ /* configure some gpios */
+ ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+ if (ret)
+ goto err_gpio;
+
+ ret = gpio_direction_output(S3C2410_GPA(1), 0);
+ if (ret)
+ goto err_gpio_conf;
+
+ s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!s3c24xx_snd_device) {
+ ret = -ENOMEM;
+ goto err_plat_alloc;
+ }
+
+ platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+ ret = platform_device_add(s3c24xx_snd_device);
+
+ if (ret) {
+ platform_device_put(s3c24xx_snd_device);
+ goto err_plat_add;
+ }
+
+ xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ platform_device_unregister(s3c24xx_snd_device);
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+ gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+ return ret;
+}
+
+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);
+ clk_put(xtal);
+ gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index 31f6d45b6384..f891eb79b575 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -89,7 +89,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to activate!");
+ pr_err("AC97: Unable to activate!");
}
static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -115,14 +115,15 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to read!");
+ pr_err("AC97: Unable to read!");
stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
addr = (stat >> 16) & 0x7f;
data = (stat & 0xffff);
if (addr != reg)
- printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
+ pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
+ reg, addr);
mutex_unlock(&s3c_ac97.lock);
@@ -151,7 +152,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
- printk(KERN_ERR "AC97: Unable to write!");
+ pr_err("AC97: Unable to write!");
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
@@ -162,6 +163,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
{
+ pr_debug("AC97: Cold reset\n");
writel(S3C_AC97_GLBCTRL_COLDRESET,
s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -178,6 +180,8 @@ static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
+ pr_debug("AC97: Warm reset\n");
+
writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
@@ -222,7 +226,7 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct s3c_dma_params *dma_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -241,7 +245,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -277,7 +281,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
return -ENODEV;
@@ -293,7 +297,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
@@ -328,10 +332,9 @@ static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
.trigger = s3c_ac97_mic_trigger,
};
-struct snd_soc_dai s3c_ac97_dai[] = {
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "s3c-ac97",
- .id = S3C_AC97_DAI_PCM,
.ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
@@ -349,7 +352,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
},
[S3C_AC97_DAI_MIC] = {
.name = "s3c-ac97-mic",
- .id = S3C_AC97_DAI_MIC,
.ac97_control = 1,
.capture = {
.stream_name = "AC97 Mic Capture",
@@ -360,7 +362,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
.ops = &s3c_ac97_mic_dai_ops,
},
};
-EXPORT_SYMBOL_GPL(s3c_ac97_dai);
static __devinit int s3c_ac97_probe(struct platform_device *pdev)
{
@@ -445,14 +446,12 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev)
ret = request_irq(irq_res->start, s3c_ac97_irq,
IRQF_DISABLED, "AC97", NULL);
if (ret < 0) {
- printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
+ dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
goto err4;
}
- s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
- s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
-
- ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+ ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
@@ -476,7 +475,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev)
{
struct resource *mem_res, *irq_res;
- snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res)
@@ -518,3 +517,4 @@ module_exit(s3c_ac97_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-ac97");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
index 278198379def..5dcedd07fdbb 100644
--- a/sound/soc/s3c24xx/s3c-ac97.h
+++ b/sound/soc/s3c24xx/s3c-ac97.h
@@ -18,6 +18,4 @@
#define S3C_AC97_DAI_PCM 0
#define S3C_AC97_DAI_MIC 1
-extern struct snd_soc_dai s3c_ac97_dai[];
-
#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
index f1b1bc4bacfb..243f79bf43bb 100644
--- a/sound/soc/s3c24xx/s3c-dma.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -146,7 +146,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
int ret = 0;
@@ -440,14 +440,14 @@ static int s3c_dma_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
- if (dai->playback.channels_min) {
+ if (dai->driver->playback.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->capture.channels_min) {
+ if (dai->driver->capture.channels_min) {
ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
@@ -457,26 +457,46 @@ static int s3c_dma_new(struct snd_card *card,
return ret;
}
-struct snd_soc_platform s3c24xx_soc_platform = {
- .name = "s3c24xx-audio",
- .pcm_ops = &s3c_dma_ops,
+static struct snd_soc_platform_driver s3c24xx_soc_platform = {
+ .ops = &s3c_dma_ops,
.pcm_new = s3c_dma_new,
.pcm_free = s3c_dma_free_dma_buffers,
};
-EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
-static int __init s3c24xx_soc_platform_init(void)
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&s3c24xx_soc_platform);
+ return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
}
-module_init(s3c24xx_soc_platform_init);
-static void __exit s3c24xx_soc_platform_exit(void)
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_platform(&s3c24xx_soc_platform);
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_pcm_driver = {
+ .driver = {
+ .name = "s3c24xx-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = s3c24xx_soc_platform_probe,
+ .remove = __devexit_p(s3c24xx_soc_platform_remove),
+};
+
+static int __init snd_s3c24xx_pcm_init(void)
+{
+ return platform_driver_register(&s3c24xx_pcm_driver);
+}
+module_init(snd_s3c24xx_pcm_init);
+
+static void __exit snd_s3c24xx_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_pcm_driver);
}
-module_exit(s3c24xx_soc_platform_exit);
+module_exit(snd_s3c24xx_pcm_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-pcm-audio");
diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h
index 69bb6bf6fc1c..748c07d7c075 100644
--- a/sound/soc/s3c24xx/s3c-dma.h
+++ b/sound/soc/s3c24xx/s3c-dma.h
@@ -25,7 +25,6 @@ struct s3c_dma_params {
#define S3C24XX_DAI_I2S 0
/* platform data */
-extern struct snd_soc_platform s3c24xx_soc_platform;
extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
#endif
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 64376b2aac73..b3866d5b19e9 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -49,7 +49,7 @@
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
{
- return cpu_dai->private_data;
+ return snd_soc_dai_get_drvdata(cpu_dai);
}
#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
@@ -307,11 +307,9 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
- struct snd_soc_dai *socdai)
+ struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -322,7 +320,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
else
dma_data = i2s->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* Working copies of register */
iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -396,12 +394,12 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+ struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
unsigned long irqs;
int ret = 0;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -640,36 +638,17 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
-int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = dai->dev;
unsigned int iismod;
i2s->dev = dev;
/* record our i2s structure for later use in the callbacks */
- dai->private_data = i2s;
-
- if (!base) {
- struct resource *res = platform_get_resource(pdev,
- IORESOURCE_MEM,
- 0);
- if (!res) {
- dev_err(dev, "Unable to get register resource\n");
- return -ENXIO;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- "s3c64xx-i2s-v4")) {
- dev_err(dev, "Unable to request register region\n");
- return -EBUSY;
- }
-
- base = res->start;
- }
+ snd_soc_dai_set_drvdata(dai, i2s);
i2s->regs = ioremap(base, 0x100);
if (i2s->regs == NULL) {
@@ -752,9 +731,10 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
#define s3c2412_i2s_resume NULL
#endif
-int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv)
{
- struct snd_soc_dai_ops *ops = dai->ops;
+ struct snd_soc_dai_ops *ops = drv->ops;
ops->trigger = s3c2412_i2s_trigger;
if (!ops->hw_params)
@@ -767,10 +747,10 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
if (!ops->delay)
ops->delay = s3c2412_i2s_delay;
- dai->suspend = s3c2412_i2s_suspend;
- dai->resume = s3c2412_i2s_resume;
+ drv->suspend = s3c2412_i2s_suspend;
+ drv->resume = s3c2412_i2s_resume;
- return snd_soc_register_dai(dai);
+ return snd_soc_register_dai(dev, drv);
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index 766f43a13d8b..d45830151484 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -66,6 +66,8 @@ struct s3c_i2sv2_info {
u32 suspend_iismod;
u32 suspend_iiscon;
u32 suspend_iispsr;
+
+ unsigned long base;
};
extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
@@ -81,23 +83,24 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
/**
* s3c_i2sv2_probe - probe for i2s device helper
- * @pdev: The platform device supplied to the original probe.
* @dai: The ASoC DAI structure supplied to the original probe.
* @i2s: Our local i2s structure to fill in.
* @base: The base address for the registers.
*/
-extern int s3c_i2sv2_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai,
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
struct s3c_i2sv2_info *i2s,
unsigned long base);
/**
* s3c_i2sv2_register_dai - register dai with soc core
- * @dai: The snd_soc_dai structure to register
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
*
* Fill in any missing fields and then register the given dai with the
* soc core.
*/
-extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+ struct snd_soc_dai_driver *drv);
#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
index 326f0a9e7e30..2e020e1b4eab 100644
--- a/sound/soc/s3c24xx/s3c-pcm.c
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -64,11 +64,6 @@ static struct s3c_dma_params s3c_pcm_stereo_in[] = {
static struct s3c_pcm_info s3c_pcm[2];
-static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
{
void __iomem *regs = pcm->regs;
@@ -83,7 +78,7 @@ static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
ctl |= S3C_PCM_CTL_TXDMA_EN;
ctl |= S3C_PCM_CTL_TXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
- ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_TXDMA_EN;
@@ -107,11 +102,14 @@ static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
ctl = readl(regs + S3C_PCM_CTL);
clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+ << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
if (on) {
ctl |= S3C_PCM_CTL_RXDMA_EN;
ctl |= S3C_PCM_CTL_RXFIFO_EN;
ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
} else {
ctl &= ~S3C_PCM_CTL_RXDMA_EN;
@@ -132,7 +130,7 @@ static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
unsigned long flags;
dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -176,8 +174,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *socdai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *dai = rtd->dai;
- struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+ 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;
@@ -192,7 +189,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
else
dma_data = pcm->dma_capture;
- snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Strictly check for sample size */
switch (params_format(params)) {
@@ -242,7 +239,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
unsigned long flags;
int ret = 0;
@@ -313,7 +310,7 @@ exit:
static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
switch (div_id) {
case S3C_PCM_SCLK_PER_FS:
@@ -330,7 +327,7 @@ static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
void __iomem *regs = pcm->regs;
u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
@@ -366,10 +363,7 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
-#define S3C_PCM_DECLARE(n) \
-{ \
- .name = "samsung-pcm", \
- .id = (n), \
+#define S3C_PCM_DAI_DECLARE \
.symmetric_rates = 1, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
@@ -383,19 +377,23 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
.channels_max = 2, \
.rates = S3C_PCM_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
- }, \
-}
+ }
-struct snd_soc_dai s3c_pcm_dai[] = {
- S3C_PCM_DECLARE(0),
- S3C_PCM_DECLARE(1),
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+ [0] = {
+ .name = "samsung-pcm.0",
+ S3C_PCM_DAI_DECLARE,
+ },
+ [1] = {
+ .name = "samsung-pcm.1",
+ S3C_PCM_DAI_DECLARE,
+ },
};
EXPORT_SYMBOL_GPL(s3c_pcm_dai);
static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
{
struct s3c_pcm_info *pcm;
- struct snd_soc_dai *dai;
struct resource *mem_res, *dmatx_res, *dmarx_res;
struct s3c_audio_pdata *pcm_pdata;
int ret;
@@ -437,9 +435,6 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
spin_lock_init(&pcm->lock);
- dai = &s3c_pcm_dai[pdev->id];
- dai->dev = &pdev->dev;
-
/* Default is 128fs */
pcm->sclk_per_fs = 128;
@@ -452,7 +447,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
clk_enable(pcm->cclk);
/* record our pcm structure for later use in the callbacks */
- dai->private_data = pcm;
+ dev_set_drvdata(&pdev->dev, pcm);
if (!request_mem_region(mem_res->start,
resource_size(mem_res), "samsung-pcm")) {
@@ -476,7 +471,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
}
clk_enable(pcm->pclk);
- ret = snd_soc_register_dai(dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
if (ret != 0) {
dev_err(&pdev->dev, "failed to get pcm_clock\n");
goto err5;
@@ -514,6 +509,8 @@ static __devexit 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);
+
iounmap(pcm->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,3 +549,4 @@ module_exit(s3c_pcm_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C PCM Controller Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
index 69ff9971692f..f60baa19387d 100644
--- a/sound/soc/s3c24xx/s3c-pcm.h
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -22,7 +22,8 @@
/* PCM_CTL Bit-Fields */
#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 709adef9d043..4a861cfa52c5 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -65,26 +65,20 @@ static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
static struct s3c_i2sv2_info s3c2412_i2s;
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
- return cpu_dai->private_data;
-}
-
-static int s3c2412_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
{
int ret;
pr_debug("Entered %s\n", __func__);
- ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+ ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
if (ret)
return ret;
s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
- s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
+ s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
if (s3c2412_i2s.iis_cclk == NULL) {
pr_err("failed to get i2sclk clock\n");
iounmap(s3c2412_i2s.regs);
@@ -108,11 +102,20 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
return 0;
}
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_disable(s3c2412_i2s.iis_cclk);
+ clk_put(s3c2412_i2s.iis_cclk);
+ iounmap(s3c2412_i2s.regs);
+
+ return 0;
+}
+
static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -152,10 +155,9 @@ static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
.hw_params = s3c2412_i2s_hw_params,
};
-struct snd_soc_dai s3c2412_i2s_dai = {
- .name = "s3c2412-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
.probe = s3c2412_i2s_probe,
+ .remove = s3c2412_i2s_remove,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -170,17 +172,36 @@ struct snd_soc_dai s3c2412_i2s_dai = {
},
.ops = &s3c2412_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+ .probe = s3c2412_iis_dev_probe,
+ .remove = s3c2412_iis_dev_remove,
+ .driver = {
+ .name = "s3c2412-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c2412_i2s_init(void)
{
- return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
+ return platform_driver_register(&s3c2412_iis_driver);
}
module_init(s3c2412_i2s_init);
static void __exit s3c2412_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c2412_i2s_dai);
+ platform_driver_unregister(&s3c2412_iis_driver);
}
module_exit(s3c2412_i2s_exit);
@@ -188,3 +209,4 @@ module_exit(s3c2412_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index 0b5686b4d5c3..01a0471ac65c 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -24,6 +24,4 @@
#define S3C2412_CLKSRC_PCLK S3C_I2SV2_CLKSRC_PCLK
#define S3C2412_CLKSRC_I2SCLK S3C_I2SV2_CLKSRC_AUDIOBUS
-extern struct snd_soc_dai s3c2412_i2s_dai;
-
#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index c3ac890a3986..e060daaa458f 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -252,7 +252,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
else
dma_data = &s3c24xx_i2s_pcm_stereo_in;
- snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
/* Working copies of register */
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -280,9 +280,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_dma_params *dma_data =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+ snd_soc_dai_get_dma_data(dai, substream);
pr_debug("Entered %s\n", __func__);
@@ -387,8 +386,7 @@ u32 s3c24xx_i2s_get_clockrate(void)
}
EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
-static int s3c24xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
{
pr_debug("Entered %s\n", __func__);
@@ -396,7 +394,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
if (s3c24xx_i2s.regs == NULL)
return -ENXIO;
- s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
+ s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
if (s3c24xx_i2s.iis_clk == NULL) {
pr_err("failed to get iis_clock\n");
iounmap(s3c24xx_i2s.regs);
@@ -465,9 +463,7 @@ static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
.set_sysclk = s3c24xx_i2s_set_sysclk,
};
-struct snd_soc_dai s3c24xx_i2s_dai = {
- .name = "s3c24xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
.probe = s3c24xx_i2s_probe,
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
@@ -483,17 +479,36 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &s3c24xx_i2s_dai_ops,
};
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+ .probe = s3c24xx_iis_dev_probe,
+ .remove = s3c24xx_iis_dev_remove,
+ .driver = {
+ .name = "s3c24xx-iis",
+ .owner = THIS_MODULE,
+ },
+};
static int __init s3c24xx_i2s_init(void)
{
- return snd_soc_register_dai(&s3c24xx_i2s_dai);
+ return platform_driver_register(&s3c24xx_iis_driver);
}
module_init(s3c24xx_i2s_init);
static void __exit s3c24xx_i2s_exit(void)
{
- snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+ platform_driver_unregister(&s3c24xx_iis_driver);
}
module_exit(s3c24xx_i2s_exit);
@@ -501,3 +516,4 @@ module_exit(s3c24xx_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h
index 726d91cf4e1c..f9ca04edacb7 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.h
@@ -32,6 +32,4 @@
u32 s3c24xx_i2s_get_clockrate(void);
-extern struct snd_soc_dai s3c24xx_i2s_dai;
-
#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 4984754f3298..c4c111442010 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -139,8 +139,10 @@ static const struct snd_kcontrol_new amp_unmute_controls[] = {
speaker_unmute_get, speaker_unmute_put),
};
-void simtec_audio_init(struct snd_soc_codec *codec)
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
if (pdata->amp_gpio > 0) {
pr_debug("%s: adding amp routes\n", __func__);
@@ -170,8 +172,8 @@ static int simtec_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 *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* Set the CODEC as the bus clock master, I2S */
@@ -319,12 +321,12 @@ EXPORT_SYMBOL_GPL(simtec_audio_pmops);
#endif
int __devinit simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev)
+ struct snd_soc_card *card)
{
struct platform_device *snd_dev;
int ret;
- socdev->card->dai_link->ops = &simtec_snd_ops;
+ card->dai_link->ops = &simtec_snd_ops;
pdata = pdev->dev.platform_data;
if (!pdata) {
@@ -353,8 +355,7 @@ int __devinit simtec_audio_core_probe(struct platform_device *pdev,
goto err_gpio;
}
- platform_set_drvdata(snd_dev, socdev);
- socdev->dev = &snd_dev->dev;
+ platform_set_drvdata(snd_dev, card);
ret = platform_device_add(snd_dev);
if (ret) {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
index e18faee30cce..e63d5ff9c41f 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.h
@@ -7,10 +7,10 @@
* published by the Free Software Foundation.
*/
-extern void simtec_audio_init(struct snd_soc_codec *codec);
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
extern int simtec_audio_core_probe(struct platform_device *pdev,
- struct snd_soc_device *socdev);
+ struct snd_soc_card *card);
extern int simtec_audio_remove(struct platform_device *pdev);
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index bdf8951af8e3..f88453735ae2 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -73,8 +73,10 @@ static const struct snd_soc_dapm_route base_map[] = {
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_hermes_init(struct snd_soc_codec *codec)
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -85,42 +87,33 @@ static int simtec_hermes_init(struct snd_soc_codec *codec)
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
}
-static struct aic3x_setup_data codec_setup = {
-};
-
static struct snd_soc_dai_link simtec_dai_aic33 = {
.name = "tlv320aic33",
.stream_name = "TLV320AIC33",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &aic3x_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_hermes_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
.name = "Simtec-Hermes",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic33,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic33 = {
- .card = &snd_soc_machine_simtec_aic33,
- .codec_dev = &soc_codec_dev_aic3x,
- .codec_data = &codec_setup,
-};
-
static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
{
dev_info(&pd->dev, "probing....\n");
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
}
static struct platform_driver simtec_audio_hermes_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 185c0acb5ce6..c0967593510d 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -62,8 +62,10 @@ static const struct snd_soc_dapm_route base_map[] = {
* Attach our controls and configure the necessary codec
* mappings for our sound card instance.
*/
-static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
snd_soc_dapm_new_controls(codec, dapm_widgets,
ARRAY_SIZE(dapm_widgets));
@@ -74,7 +76,7 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
snd_soc_dapm_enable_pin(codec, "Line Out");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
- simtec_audio_init(codec);
+ simtec_audio_init(rtd);
snd_soc_dapm_sync(codec);
return 0;
@@ -83,28 +85,23 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link simtec_dai_aic23 = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
- .cpu_dai = &s3c24xx_i2s_dai,
- .codec_dai = &tlv320aic23_dai,
+ .codec_name = "tlv320aic3x-codec.0-0x1a",
+ .cpu_dai_name = "s3c24xx-i2s",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
.init = simtec_tlv320aic23_init,
};
/* simtec audio machine driver */
static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
.name = "Simtec",
- .platform = &s3c24xx_soc_platform,
.dai_link = &simtec_dai_aic23,
.num_links = 1,
};
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic23 = {
- .card = &snd_soc_machine_simtec_aic23,
- .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
{
- return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23);
+ return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
}
static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index 052d59659c29..bd48ffbde880 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -133,8 +133,8 @@ static int s3c24xx_uda134x_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 *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int clk = 0;
int ret = 0;
int clk_source, fs_mode;
@@ -227,14 +227,15 @@ static struct snd_soc_ops s3c24xx_uda134x_ops = {
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
.name = "UDA134X",
.stream_name = "UDA134X",
- .codec_dai = &uda134x_dai,
- .cpu_dai = &s3c24xx_i2s_dai,
+ .codec_name = "uda134x-hifi",
+ .codec_dai_name = "uda134x-hifi",
+ .cpu_dai_name = "s3c24xx-i2s",
.ops = &s3c24xx_uda134x_ops,
+ .platform_name = "s3c24xx-pcm-audio",
};
static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
.name = "S3C24XX_UDA134X",
- .platform = &s3c24xx_soc_platform,
.dai_link = &s3c24xx_uda134x_dai_link,
.num_links = 1,
};
@@ -256,6 +257,7 @@ static void setmode(int v)
gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
}
+/* FIXME - This must be codec platform data but in which board file ?? */
static struct uda134x_platform_data s3c24xx_uda134x = {
.l3 = {
.setdat = setdat,
@@ -270,12 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = {
},
};
-static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
- .card = &snd_soc_s3c24xx_uda134x,
- .codec_dev = &soc_codec_dev_uda134x,
- .codec_data = &s3c24xx_uda134x,
-};
-
static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
{
if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
@@ -325,8 +321,7 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
}
platform_set_drvdata(s3c24xx_uda134x_snd_device,
- &s3c24xx_uda134x_snd_devdata);
- s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+ &snd_soc_s3c24xx_uda134x);
ret = platform_device_add(s3c24xx_uda134x_snd_device);
if (ret) {
printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
index 06db130030a1..a9628472ebfe 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -16,9 +16,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-h.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -39,34 +37,23 @@ static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
static struct s3c_i2sv2_info s3c64xx_i2sv4;
-struct snd_soc_dai s3c64xx_i2s_v4_dai;
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
-}
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ int ret = 0;
-static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
-{
- /* configure GPIO for i2s port */
- s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
- s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
- s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
- s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+ snd_soc_dai_set_drvdata(dai, i2s);
- return 0;
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+
+ return ret;
}
static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
struct s3c_dma_params *dma_data;
u32 iismod;
@@ -104,51 +91,79 @@ static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
.hw_params = s3c_i2sv4_hw_params,
};
+static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
+ .symmetric_rates = 1,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .probe = s3c64xx_i2sv4_probe,
+ .ops = &s3c64xx_i2sv4_dai_ops,
+};
+
static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
+ struct resource *res;
int ret;
i2s = &s3c64xx_i2sv4;
- dai = &s3c64xx_i2s_v4_dai;
-
- if (dai->dev) {
- dev_dbg(dai->dev, "%s: \
- I2Sv4 instance already registered!\n", __func__);
- return -EBUSY;
- }
-
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s-v4";
- dai->id = 0;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2sv4_probe;
- dai->ops = &s3c64xx_i2sv4_dai_ops;
i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
- i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->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;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s-v4")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
if (IS_ERR(i2s->iis_cclk)) {
dev_err(&pdev->dev, "failed to get audio-bus\n");
@@ -158,19 +173,13 @@ static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
clk_enable(i2s->iis_cclk);
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
+ ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
if (ret != 0)
goto err_i2sv2;
return 0;
err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
clk_put(i2s->iis_cclk);
err:
return ret;
@@ -178,7 +187,18 @@ err:
static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+ struct resource *res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+ clk_put(i2s->iis_cclk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ else
+ dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
+
return 0;
}
@@ -207,3 +227,4 @@ module_exit(s3c64xx_i2sv4_exit);
MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 1d85cb85a7d2..ae7acb6c4f1d 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -12,15 +12,15 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <sound/soc.h>
-#include <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -46,45 +46,107 @@ static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
-struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
{
- return cpu_dai->private_data;
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+ return i2s->iis_cclk;
+ else
+ return i2s->iis_pclk;
}
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
-static int s3c64xx_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
{
- /* configure GPIO for i2s port */
- switch (dai->id) {
- case 0:
- s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
- s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
- break;
- case 1:
- s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
- s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
- s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ struct s3c_i2sv2_info *i2s;
+ int ret;
+
+ if (dai->id >= MAX_I2SV3) {
+ dev_err(dai->dev, "id %d out of range\n", dai->id);
+ return -EINVAL;
+ }
+
+ i2s = &s3c64xx_i2s[dai->id];
+ snd_soc_dai_set_drvdata(dai, i2s);
+
+ i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
+ if (IS_ERR(i2s->iis_cclk)) {
+ dev_err(dai->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(i2s->iis_cclk);
+ goto err;
}
+ clk_enable(i2s->iis_cclk);
+
+ ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
+ if (ret)
+ goto err_clk;
+
return 0;
+
+err_clk:
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+err:
+ kfree(i2s);
+ return ret;
}
+static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable(i2s->iis_cclk);
+ clk_put(i2s->iis_cclk);
+ kfree(i2s);
+ return 0;
+}
static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
+static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
+{
+ .name = "s3c64xx-i2s-0",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+}, {
+ .name = "s3c64xx-i2s-1",
+ .probe = s3c64xx_i2s_probe,
+ .remove = s3c64xx_i2s_remove,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,},
+ .ops = &s3c64xx_i2s_dai_ops,
+ .symmetric_rates = 1,
+},};
+
static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
{
+ struct s3c_audio_pdata *i2s_pdata;
struct s3c_i2sv2_info *i2s;
- struct snd_soc_dai *dai;
- int ret;
+ struct resource *res;
+ int i, ret;
if (pdev->id >= MAX_I2SV3) {
dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
@@ -92,74 +154,63 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
}
i2s = &s3c64xx_i2s[pdev->id];
- dai = &s3c64xx_i2s_dai[pdev->id];
- dai->dev = &pdev->dev;
- dai->name = "s3c64xx-i2s";
- dai->id = pdev->id;
- dai->symmetric_rates = 1;
- dai->playback.channels_min = 2;
- dai->playback.channels_max = 2;
- dai->playback.rates = S3C64XX_I2S_RATES;
- dai->playback.formats = S3C64XX_I2S_FMTS;
- dai->capture.channels_min = 2;
- dai->capture.channels_max = 2;
- dai->capture.rates = S3C64XX_I2S_RATES;
- dai->capture.formats = S3C64XX_I2S_FMTS;
- dai->probe = s3c64xx_i2s_probe;
- dai->ops = &s3c64xx_i2s_dai_ops;
-
- i2s->feature |= S3C_FEATURE_CDCLKCON;
i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
- if (pdev->id == 0) {
- i2s->dma_capture->channel = DMACH_I2S0_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S0_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
- } else {
- i2s->dma_capture->channel = DMACH_I2S1_IN;
- i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
- i2s->dma_playback->channel = DMACH_I2S1_OUT;
- i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+ return -ENXIO;
+ }
+ i2s->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;
+ }
+ i2s->dma_capture->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+ return -ENXIO;
}
+ if (!request_mem_region(res->start, resource_size(res),
+ "s3c64xx-i2s")) {
+ dev_err(&pdev->dev, "Unable to request SFR region\n");
+ return -EBUSY;
+ }
+ i2s->base = res->start;
+
+ i2s_pdata = pdev->dev.platform_data;
+ if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+ i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
+ i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
+
i2s->dma_capture->client = &s3c64xx_dma_client_in;
i2s->dma_capture->dma_size = 4;
i2s->dma_playback->client = &s3c64xx_dma_client_out;
i2s->dma_playback->dma_size = 4;
- i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
- if (IS_ERR(i2s->iis_cclk)) {
- dev_err(&pdev->dev, "failed to get audio-bus\n");
- ret = PTR_ERR(i2s->iis_cclk);
- goto err;
+ for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
+ ret = s3c_i2sv2_register_dai(&pdev->dev, i,
+ &s3c64xx_i2s_dai[i]);
+ if (ret != 0)
+ return ret;
}
- clk_enable(i2s->iis_cclk);
-
- ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
- if (ret)
- goto err_clk;
-
- ret = s3c_i2sv2_register_dai(dai);
- if (ret != 0)
- goto err_i2sv2;
-
return 0;
-
-err_i2sv2:
- /* Not implemented for I2Sv2 core yet */
-err_clk:
- clk_put(i2s->iis_cclk);
-err:
- return ret;
}
static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Device removal not yet supported\n");
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
return 0;
}
@@ -188,3 +239,4 @@ module_exit(s3c64xx_i2s_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index 7a40f43d1d51..de4075d26f0c 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -36,7 +36,6 @@ struct clk;
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE)
-extern struct snd_soc_dai s3c64xx_i2s_dai[];
-extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
index b480348140b0..dd20ca7f4681 100644
--- a/sound/soc/s3c24xx/smartq_wm8987.c
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -211,8 +211,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
{
.name = "wm8987",
.stream_name = "SmartQ Hi-Fi",
- .cpu_dai = &s3c64xx_i2s_dai[0],
- .codec_dai = &wm8750_dai,
+ .cpu_dai_name = "s3c64xx-i2s.0",
+ .codec_dai_name = "wm8750-hifi",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8750-codec.0-0x1a",
.init = smartq_wm8987_init,
.ops = &smartq_hifi_ops,
},
@@ -220,16 +222,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
static struct snd_soc_card snd_soc_smartq = {
.name = "SmartQ",
- .platform = &s3c24xx_soc_platform,
.dai_link = smartq_dai,
.num_links = ARRAY_SIZE(smartq_dai),
};
-static struct snd_soc_device smartq_snd_devdata = {
- .card = &snd_soc_smartq,
- .codec_dev = &soc_codec_dev_wm8750,
-};
-
static struct platform_device *smartq_snd_device;
static int __init smartq_init(void)
@@ -245,8 +241,7 @@ static int __init smartq_init(void)
if (!smartq_snd_device)
return -ENOMEM;
- platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
- smartq_snd_devdata.dev = &smartq_snd_device->dev;
+ platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
ret = platform_device_add(smartq_snd_device);
if (ret) {
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index 362258835e8d..4613288c2772 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -19,7 +19,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include "../codecs/ac97.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -29,23 +28,19 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &ac97_dai,
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "ac97-hifi",
+ .codec_name = "ac97-codec",
+ .platform_name = "s3c24xx-pcm-audio",
},
};
static struct snd_soc_card smdk2443 = {
.name = "SMDK2443",
- .platform = &s3c24xx_soc_platform,
.dai_link = smdk2443_dai,
.num_links = ARRAY_SIZE(smdk2443_dai),
};
-static struct snd_soc_device smdk2443_snd_ac97_devdata = {
- .card = &smdk2443,
- .codec_dev = &soc_codec_dev_ac97,
-};
-
static struct platform_device *smdk2443_snd_ac97_device;
static int __init smdk2443_init(void)
@@ -56,9 +51,7 @@ static int __init smdk2443_init(void)
if (!smdk2443_snd_ac97_device)
return -ENOMEM;
- platform_set_drvdata(smdk2443_snd_ac97_device,
- &smdk2443_snd_ac97_devdata);
- smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+ platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
ret = platform_device_add(smdk2443_snd_ac97_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 07e8e51d10d6..052e499b68d1 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -22,6 +22,12 @@
#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
#define SMDK64XX_WM8580_FREQ 12000000
@@ -29,8 +35,8 @@ static int smdk64xx_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->dai->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out;
int bfs, rfs, ret;
@@ -107,14 +113,13 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* Explicitly set WM8580-DAC to source from MCLK */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
- WM8580_CLKSRC_MCLK);
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+ SMDK64XX_WM8580_FREQ, pll_out);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
- SMDK64XX_WM8580_FREQ, pll_out);
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+ pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
@@ -138,9 +143,9 @@ static struct snd_soc_ops smdk64xx_ops = {
/* SMDK64xx Playback widgets */
static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
- SND_SOC_DAPM_HP("Front-L/R", NULL),
- SND_SOC_DAPM_HP("Center/Sub", NULL),
- SND_SOC_DAPM_HP("Rear-L/R", NULL),
+ SND_SOC_DAPM_HP("Front", NULL),
+ SND_SOC_DAPM_HP("Center+Sub", NULL),
+ SND_SOC_DAPM_HP("Rear", NULL),
};
/* SMDK64xx Capture widgets */
@@ -162,20 +167,22 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
/* SMDK-PAIFRX connections */
static const struct snd_soc_dapm_route audio_map_rx[] = {
/* Front Left/Right are fed VOUT1L/R */
- {"Front-L/R", NULL, "VOUT1L"},
- {"Front-L/R", NULL, "VOUT1R"},
+ {"Front", NULL, "VOUT1L"},
+ {"Front", NULL, "VOUT1R"},
/* Center/Sub are fed VOUT2L/R */
- {"Center/Sub", NULL, "VOUT2L"},
- {"Center/Sub", NULL, "VOUT2R"},
+ {"Center+Sub", NULL, "VOUT2L"},
+ {"Center+Sub", NULL, "VOUT2R"},
/* Rear Left/Right are fed VOUT3L/R */
- {"Rear-L/R", NULL, "VOUT3L"},
- {"Rear-L/R", NULL, "VOUT3R"},
+ {"Rear", NULL, "VOUT3L"},
+ {"Rear", NULL, "VOUT3R"},
};
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Capture widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
ARRAY_SIZE(wm8580_dapm_widgets_cpt));
@@ -194,8 +201,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
return 0;
}
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_codec *codec = rtd->codec;
+
/* Add smdk64xx specific Playback widgets */
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
ARRAY_SIZE(wm8580_dapm_widgets_pbk));
@@ -213,33 +222,31 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paifrx,
.ops = &smdk64xx_ops,
},
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai = &s3c64xx_i2s_v4_dai,
- .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+ .cpu_dai_name = "s3c64xx-iis-v4",
+ .codec_dai_name = "wm8580-hifi-capture",
+ .platform_name = "s3c24xx-pcm-audio",
+ .codec_name = "wm8580-codec.0-001b",
.init = smdk64xx_wm8580_init_paiftx,
.ops = &smdk64xx_ops,
},
};
static struct snd_soc_card smdk64xx = {
- .name = "smdk64xx",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK64xx 5.1",
.dai_link = smdk64xx_dai,
.num_links = ARRAY_SIZE(smdk64xx_dai),
};
-static struct snd_soc_device smdk64xx_snd_devdata = {
- .card = &smdk64xx,
- .codec_dev = &soc_codec_dev_wm8580,
-};
-
static struct platform_device *smdk64xx_snd_device;
static int __init smdk64xx_audio_init(void)
@@ -250,8 +257,7 @@ static int __init smdk64xx_audio_init(void)
if (!smdk64xx_snd_device)
return -ENOMEM;
- platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
- smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+ platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
ret = platform_device_add(smdk64xx_snd_device);
if (ret)
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
new file mode 100644
index 000000000000..f31d22ad7c88
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk_spdif.c
@@ -0,0 +1,223 @@
+/*
+ * smdk_spdif.c -- S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * 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 <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+ struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+ int ret;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mout_epll = clk_get(NULL, "mout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out1;
+ }
+
+ sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+ if (IS_ERR(sclk_audio0)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out2;
+ }
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+ __func__);
+ ret = -EINVAL;
+ goto out3;
+ }
+
+ /* Set audio clock heirachy for S/PDIF */
+ clk_set_parent(mout_epll, fout_epll);
+ clk_set_parent(sclk_audio0, mout_epll);
+ clk_set_parent(sclk_spdif, sclk_audio0);
+
+ clk_put(sclk_spdif);
+out3:
+ clk_put(sclk_audio0);
+out2:
+ clk_put(mout_epll);
+out1:
+ clk_put(fout_epll);
+
+ return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's heirachy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+ unsigned long audio_rate)
+{
+ struct clk *fout_epll, *sclk_spdif;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(fout_epll, epll_rate);
+ clk_put(fout_epll);
+
+ sclk_spdif = clk_get(NULL, "sclk_spdif");
+ if (IS_ERR(sclk_spdif)) {
+ printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+ return -ENOENT;
+ }
+
+ clk_set_rate(sclk_spdif, audio_rate);
+ clk_put(sclk_spdif);
+
+ return 0;
+}
+
+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;
+ unsigned long pll_out, rclk_rate;
+ int ret, ratio;
+
+ switch (params_rate(params)) {
+ case 44100:
+ pll_out = 45158400;
+ break;
+ case 32000:
+ case 48000:
+ case 96000:
+ pll_out = 49152000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+ * modify S/PDIF ASoC machine driver.
+ */
+ ratio = 512;
+ rclk_rate = params_rate(params) * ratio;
+
+ /* Set audio source clock rates */
+ ret = set_audio_clock_rate(pll_out, rclk_rate);
+ if (ret < 0)
+ return ret;
+
+ /* Set S/PDIF uses internal source clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_card smdk;
+
+static struct snd_soc_dai_link smdk_dai = {
+ .name = "S/PDIF",
+ .stream_name = "S/PDIF PCM Playback",
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "samsung-spdif",
+ .codec_dai_name = "dit-hifi",
+ .codec_name = "spdif-dit",
+ .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+ .name = "SMDK-S/PDIF",
+ .dai_link = &smdk_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+ int ret;
+
+ smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+ if (!smdk_snd_spdif_dit_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(smdk_snd_spdif_dit_device);
+ if (ret)
+ goto err2;
+
+ smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_spdif_device) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+ ret = platform_device_add(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ /* Set audio clock heirachy manually */
+ ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+err1:
+ platform_device_put(smdk_snd_spdif_device);
+err2:
+ platform_device_put(smdk_snd_spdif_dit_device);
+ return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+ platform_device_unregister(smdk_snd_spdif_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 5527b9e88c98..33ba8fdbcf07 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -15,7 +15,6 @@
#include <linux/device.h>
#include <sound/soc.h>
-#include "../codecs/wm9713.h"
#include "s3c-dma.h"
#include "s3c-ac97.h"
@@ -46,46 +45,57 @@ static struct snd_soc_card smdk;
static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
- .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
- .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .platform_name = "s3c24xx-pcm-audio",
+ .cpu_dai_name = "s3c-ac97",
+ .codec_dai_name = "wm9713-hifi",
+ .codec_name = "wm9713-codec",
};
static struct snd_soc_card smdk = {
- .name = "SMDK",
- .platform = &s3c24xx_soc_platform,
+ .name = "SMDK WM9713",
.dai_link = &smdk_dai,
.num_links = 1,
};
-static struct snd_soc_device smdk_snd_ac97_devdata = {
- .card = &smdk,
- .codec_dev = &soc_codec_dev_wm9713,
-};
-
+static struct platform_device *smdk_snd_wm9713_device;
static struct platform_device *smdk_snd_ac97_device;
static int __init smdk_init(void)
{
int ret;
- smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!smdk_snd_ac97_device)
+ smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+ if (!smdk_snd_wm9713_device)
return -ENOMEM;
- platform_set_drvdata(smdk_snd_ac97_device,
- &smdk_snd_ac97_devdata);
- smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
+ ret = platform_device_add(smdk_snd_wm9713_device);
+ if (ret)
+ goto err;
+
+ smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk_snd_ac97_device) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(smdk_snd_ac97_device, &smdk);
ret = platform_device_add(smdk_snd_ac97_device);
- if (ret)
+ if (ret) {
platform_device_put(smdk_snd_ac97_device);
+ goto err;
+ }
+ return 0;
+err:
+ platform_device_put(smdk_snd_wm9713_device);
return ret;
}
static void __exit smdk_exit(void)
{
platform_device_unregister(smdk_snd_ac97_device);
+ platform_device_unregister(smdk_snd_wm9713_device);
}
module_init(smdk_init);
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
new file mode 100644
index 000000000000..ce554e9cabcc
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.c
@@ -0,0 +1,501 @@
+/* sound/soc/s3c24xx/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON 0x00
+#define CON 0x04
+#define BSTAS 0x08
+#define CSTAS 0x0C
+#define DATA_OUTBUF 0x10
+#define DCNT 0x14
+#define BSTAS_S 0x18
+#define DCNT_S 0x1C
+
+#define CLKCTL_MASK 0x7
+#define CLKCTL_MCLK_EXT (0x1 << 2)
+#define CLKCTL_PWR_ON (0x1 << 0)
+
+#define CON_MASK 0x3ffffff
+#define CON_FIFO_TH_SHIFT 19
+#define CON_FIFO_TH_MASK (0x7 << 19)
+#define CON_USERDATA_23RDBIT (0x1 << 12)
+
+#define CON_SW_RESET (0x1 << 5)
+
+#define CON_MCLKDIV_MASK (0x3 << 3)
+#define CON_MCLKDIV_256FS (0x0 << 3)
+#define CON_MCLKDIV_384FS (0x1 << 3)
+#define CON_MCLKDIV_512FS (0x2 << 3)
+
+#define CON_PCM_MASK (0x3 << 1)
+#define CON_PCM_16BIT (0x0 << 1)
+#define CON_PCM_20BIT (0x1 << 1)
+#define CON_PCM_24BIT (0x2 << 1)
+
+#define CON_PCM_DATA (0x1 << 0)
+
+#define CSTAS_MASK 0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK (0xF << 24)
+#define CSTAS_SAMP_FREQ_44 (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48 (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32 (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96 (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+ unsigned long clk_rate;
+ struct clk *pclk;
+ struct clk *sclk;
+ u32 saved_clkcon;
+ u32 saved_con;
+ u32 saved_cstas;
+ struct s3c_dma_params *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+ .name = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+ void __iomem *regs = spdif->regs;
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+ if (on)
+ writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+ else
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clkcon = readl(spdif->regs + CLKCON);
+
+ if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+ clkcon &= ~CLKCTL_MCLK_EXT;
+ else
+ clkcon |= CLKCTL_MCLK_EXT;
+
+ writel(clkcon, spdif->regs + CLKCON);
+
+ spdif->clk_rate = freq;
+
+ return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 1);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&spdif->lock, flags);
+ spdif_snd_txctrl(spdif, 0);
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+ 512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ struct s3c_dma_params *dma_data;
+ u32 con, clkcon, cstas;
+ unsigned long flags;
+ int i, ratio;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = spdif->dma_playback;
+ else {
+ dev_err(spdif->dev, "Capture is not supported\n");
+ return -EINVAL;
+ }
+
+ snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+ spin_lock_irqsave(&spdif->lock, flags);
+
+ con = readl(regs + CON) & CON_MASK;
+ cstas = readl(regs + CSTAS) & CSTAS_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ con &= ~CON_FIFO_TH_MASK;
+ con |= (0x7 << CON_FIFO_TH_SHIFT);
+ con |= CON_USERDATA_23RDBIT;
+ con |= CON_PCM_DATA;
+
+ con &= ~CON_PCM_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ con |= CON_PCM_16BIT;
+ break;
+ default:
+ dev_err(spdif->dev, "Unsupported data size.\n");
+ goto err;
+ }
+
+ ratio = spdif->clk_rate / params_rate(params);
+ for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+ if (ratio == spdif_sysclk_ratios[i])
+ break;
+ if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+ dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+ spdif->clk_rate, params_rate(params));
+ goto err;
+ }
+
+ con &= ~CON_MCLKDIV_MASK;
+ switch (ratio) {
+ case 256:
+ con |= CON_MCLKDIV_256FS;
+ break;
+ case 384:
+ con |= CON_MCLKDIV_384FS;
+ break;
+ case 512:
+ con |= CON_MCLKDIV_512FS;
+ break;
+ }
+
+ cstas &= ~CSTAS_SAMP_FREQ_MASK;
+ switch (params_rate(params)) {
+ case 44100:
+ cstas |= CSTAS_SAMP_FREQ_44;
+ break;
+ case 48000:
+ cstas |= CSTAS_SAMP_FREQ_48;
+ break;
+ case 32000:
+ cstas |= CSTAS_SAMP_FREQ_32;
+ break;
+ case 96000:
+ cstas |= CSTAS_SAMP_FREQ_96;
+ break;
+ default:
+ dev_err(spdif->dev, "Invalid sampling rate %d\n",
+ params_rate(params));
+ goto err;
+ }
+
+ cstas &= ~CSTAS_CATEGORY_MASK;
+ cstas |= CSTAS_CATEGORY_CODE_CDP;
+ cstas |= CSTAS_NO_COPYRIGHT;
+
+ writel(con, regs + CON);
+ writel(cstas, regs + CSTAS);
+ writel(clkcon, regs + CLKCON);
+
+ spin_unlock_irqrestore(&spdif->lock, flags);
+
+ return 0;
+err:
+ spin_unlock_irqrestore(&spdif->lock, flags);
+ return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+ void __iomem *regs = spdif->regs;
+ u32 con, clkcon;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ con = readl(regs + CON) & CON_MASK;
+ clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+ writel(con | CON_SW_RESET, regs + CON);
+ cpu_relax();
+
+ writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+ u32 con = spdif->saved_con;
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+ spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+ spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+ writel(con | CON_SW_RESET, spdif->regs + CON);
+ cpu_relax();
+
+ return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+ writel(spdif->saved_con, spdif->regs + CON);
+ writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+ return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+ .set_sysclk = spdif_set_sysclk,
+ .trigger = spdif_trigger,
+ .hw_params = spdif_hw_params,
+ .shutdown = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+ .name = "samsung-spdif",
+ .playback = {
+ .stream_name = "S/PDIF Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+ .ops = &spdif_dai_ops,
+ .suspend = spdif_suspend,
+ .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+ struct s3c_audio_pdata *spdif_pdata;
+ struct resource *mem_res, *dma_res;
+ struct samsung_spdif_info *spdif;
+ int ret;
+
+ spdif_pdata = pdev->dev.platform_data;
+
+ dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+ dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dma_res) {
+ dev_err(&pdev->dev, "Unable to get dma resource.\n");
+ 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;
+ }
+
+ if (spdif_pdata && spdif_pdata->cfg_gpio
+ && spdif_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+ return -EINVAL;
+ }
+
+ spdif = &spdif_info;
+ spdif->dev = &pdev->dev;
+
+ spin_lock_init(&spdif->lock);
+
+ spdif->pclk = 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);
+
+ spdif->sclk = 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);
+
+ /* Request S/PDIF Register's memory region */
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-spdif")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ spdif->regs = ioremap(mem_res->start, 0x100);
+ if (spdif->regs == NULL) {
+ dev_err(&pdev->dev, "Cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ dev_set_drvdata(&pdev->dev, spdif);
+
+ ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "fail to register dai\n");
+ goto err4;
+ }
+
+ spdif_stereo_out.dma_size = 2;
+ spdif_stereo_out.client = &spdif_dma_client_out;
+ spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+ spdif_stereo_out.channel = dma_res->start;
+
+ spdif->dma_playback = &spdif_stereo_out;
+
+ 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);
+err1:
+ clk_disable(spdif->pclk);
+ clk_put(spdif->pclk);
+err0:
+ return ret;
+}
+
+static __devexit 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);
+
+ return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+ .probe = spdif_probe,
+ .remove = spdif_remove,
+ .driver = {
+ .name = "samsung-spdif",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init spdif_init(void)
+{
+ return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+ platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
new file mode 100644
index 000000000000..3ed55592710f
--- /dev/null
+++ b/sound/soc/s3c24xx/spdif.h
@@ -0,0 +1,19 @@
+/* sound/soc/s3c24xx/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK 0
+#define SND_SOC_SPDIF_EXT_MCLK 1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */