aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt38
-rw-r--r--include/sound/simple_card_utils.h8
-rw-r--r--sound/soc/codecs/rt5665.c11
-rw-r--r--sound/soc/codecs/rt5670.c16
-rw-r--r--sound/soc/codecs/rt5670.h1
-rw-r--r--sound/soc/codecs/rt5677-spi.c1
-rw-r--r--sound/soc/generic/simple-card-utils.c5
-rw-r--r--sound/soc/generic/simple-scu-card.c113
-rw-r--r--sound/soc/samsung/Kconfig58
-rw-r--r--sound/soc/samsung/Makefile9
-rw-r--r--sound/soc/samsung/ac97.c437
-rw-r--r--sound/soc/samsung/i2s.c5
-rw-r--r--sound/soc/samsung/ln2440sbc_alc650.c72
-rw-r--r--sound/soc/samsung/pcm.c60
-rw-r--r--sound/soc/samsung/regs-ac97.h66
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c49
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c79
-rw-r--r--sound/soc/samsung/smdk2443_wm9710.c68
-rw-r--r--sound/soc/samsung/smdk_wm8580.c30
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c175
-rw-r--r--sound/soc/samsung/smdk_wm9713.c108
-rw-r--r--sound/soc/samsung/tm2_wm5110.c552
22 files changed, 751 insertions, 1210 deletions
diff --git a/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt b/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
new file mode 100644
index 000000000000..94442e5673b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/samsung,tm2-audio.txt
@@ -0,0 +1,38 @@
1Samsung Exynos5433 TM2(E) audio complex with WM5110 codec
2
3Required properties:
4
5 - compatible : "samsung,tm2-audio"
6 - model : the user-visible name of this sound complex
7 - audio-codec : the phandle of the wm5110 audio codec node,
8 as described in ../mfd/arizona.txt
9 - i2s-controller : the phandle of the I2S controller
10 - audio-amplifier : the phandle of the MAX98504 amplifier
11 - samsung,audio-routing : a list of the connections between audio components;
12 each entry is a pair of strings, the first being the
13 connection's sink, the second being the connection's
14 source; valid names for sources and sinks are the
15 WM5110's and MAX98504's pins and the jacks on the
16 board: HP, SPK, Main Mic, Sub Mic, Third Mic,
17 Headset Mic
18 - mic-bias-gpios : GPIO pin that enables the Main Mic bias regulator
19
20
21Example:
22
23sound {
24 compatible = "samsung,tm2-audio";
25 audio-codec = <&wm5110>;
26 i2s-controller = <&i2s0>;
27 audio-amplifier = <&max98504>;
28 mic-bias-gpios = <&gpr3 2 0>;
29 model = "wm5110";
30 samsung,audio-routing =
31 "HP", "HPOUT1L",
32 "HP", "HPOUT1R",
33 "SPK", "SPKOUT",
34 "SPKOUT", "HPOUT2L",
35 "SPKOUT", "HPOUT2R",
36 "Main Mic", "MICBIAS2",
37 "IN1R", "Main Mic";
38};
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index fd6412551145..64e90ca9ad32 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * simple_card_core.h 2 * simple_card_utils.h
3 * 3 *
4 * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 4 * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5 * 5 *
@@ -7,8 +7,8 @@
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10#ifndef __SIMPLE_CARD_CORE_H 10#ifndef __SIMPLE_CARD_UTILS_H
11#define __SIMPLE_CARD_CORE_H 11#define __SIMPLE_CARD_UTILS_H
12 12
13#include <sound/soc.h> 13#include <sound/soc.h>
14 14
@@ -68,4 +68,4 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
68 68
69int asoc_simple_card_clean_reference(struct snd_soc_card *card); 69int asoc_simple_card_clean_reference(struct snd_soc_card *card);
70 70
71#endif /* __SIMPLE_CARD_CORE_H */ 71#endif /* __SIMPLE_CARD_UTILS_H */
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 34254fd47efe..324461e985b3 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4587,7 +4587,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
4587 pr_err("HP Calibration Failure\n"); 4587 pr_err("HP Calibration Failure\n");
4588 regmap_write(rt5665->regmap, RT5665_RESET, 0); 4588 regmap_write(rt5665->regmap, RT5665_RESET, 0);
4589 regcache_cache_bypass(rt5665->regmap, false); 4589 regcache_cache_bypass(rt5665->regmap, false);
4590 return; 4590 goto out_unlock;
4591 } 4591 }
4592 4592
4593 count++; 4593 count++;
@@ -4606,7 +4606,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
4606 pr_err("MONO Calibration Failure\n"); 4606 pr_err("MONO Calibration Failure\n");
4607 regmap_write(rt5665->regmap, RT5665_RESET, 0); 4607 regmap_write(rt5665->regmap, RT5665_RESET, 0);
4608 regcache_cache_bypass(rt5665->regmap, false); 4608 regcache_cache_bypass(rt5665->regmap, false);
4609 return; 4609 goto out_unlock;
4610 } 4610 }
4611 4611
4612 count++; 4612 count++;
@@ -4621,6 +4621,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
4621 regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); 4621 regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
4622 regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); 4622 regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
4623 4623
4624out_unlock:
4624 mutex_unlock(&rt5665->calibrate_mutex); 4625 mutex_unlock(&rt5665->calibrate_mutex);
4625} 4626}
4626 4627
@@ -4676,11 +4677,9 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
4676 } 4677 }
4677 4678
4678 if (gpio_is_valid(rt5665->pdata.ldo1_en)) { 4679 if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
4679 if (devm_gpio_request(&i2c->dev, rt5665->pdata.ldo1_en, 4680 if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
4680 "rt5665")) 4681 GPIOF_OUT_INIT_HIGH, "rt5665"))
4681 dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); 4682 dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
4682 else if (gpio_direction_output(rt5665->pdata.ldo1_en, 1))
4683 dev_err(&i2c->dev, "Fail gpio_direction gpio_ldo\n");
4684 } 4683 }
4685 4684
4686 /* Sleep for 300 ms miniumum */ 4685 /* Sleep for 300 ms miniumum */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 49caf1393aeb..97bafac3bc15 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
2618 RT5670_OSW_L_DIS | RT5670_OSW_R_DIS); 2618 RT5670_OSW_L_DIS | RT5670_OSW_R_DIS);
2619 snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1); 2619 snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1);
2620 snd_soc_update_bits(codec, RT5670_PWR_ANLG1, 2620 snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
2621 RT5670_LDO_SEL_MASK, 0x3); 2621 RT5670_LDO_SEL_MASK, 0x5);
2622 } 2622 }
2623 break; 2623 break;
2624 case SND_SOC_BIAS_STANDBY: 2624 case SND_SOC_BIAS_STANDBY:
@@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
2626 RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | 2626 RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
2627 RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); 2627 RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
2628 snd_soc_update_bits(codec, RT5670_PWR_ANLG1, 2628 snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
2629 RT5670_LDO_SEL_MASK, 0x1); 2629 RT5670_LDO_SEL_MASK, 0x3);
2630 break; 2630 break;
2631 case SND_SOC_BIAS_OFF: 2631 case SND_SOC_BIAS_OFF:
2632 if (rt5670->pdata.jd_mode) 2632 if (rt5670->pdata.jd_mode)
@@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
2813#ifdef CONFIG_ACPI 2813#ifdef CONFIG_ACPI
2814static const struct acpi_device_id rt5670_acpi_match[] = { 2814static const struct acpi_device_id rt5670_acpi_match[] = {
2815 { "10EC5670", 0}, 2815 { "10EC5670", 0},
2816 { "10EC5672", 0},
2816 { }, 2817 { },
2817}; 2818};
2818MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); 2819MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
@@ -2826,6 +2827,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
2826 DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), 2827 DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
2827 }, 2828 },
2828 }, 2829 },
2830 {
2831 .ident = "Dell Wyse 3040",
2832 .matches = {
2833 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
2834 DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
2835 },
2836 },
2829 {} 2837 {}
2830}; 2838};
2831 2839
@@ -2889,6 +2897,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
2889 if (ret != 0) 2897 if (ret != 0)
2890 dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); 2898 dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
2891 2899
2900 regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC,
2901 RT5670_MCLK_DET, RT5670_MCLK_DET);
2902
2892 if (rt5670->pdata.in2_diff) 2903 if (rt5670->pdata.in2_diff)
2893 regmap_update_bits(rt5670->regmap, RT5670_IN2, 2904 regmap_update_bits(rt5670->regmap, RT5670_IN2,
2894 RT5670_IN_DF2, RT5670_IN_DF2); 2905 RT5670_IN_DF2, RT5670_IN_DF2);
@@ -2903,7 +2914,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
2903 RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); 2914 RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
2904 regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, 2915 regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2,
2905 RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); 2916 RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT);
2906 regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8);
2907 } 2917 }
2908 2918
2909 if (rt5670->pdata.jd_mode) { 2919 if (rt5670->pdata.jd_mode) {
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index 3f1b0f1df809..5ba485cae4e6 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -1914,6 +1914,7 @@ enum {
1914#define RT5670_IF1_ADC1_IN2_SFT 11 1914#define RT5670_IF1_ADC1_IN2_SFT 11
1915#define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10) 1915#define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10)
1916#define RT5670_IF1_ADC2_IN1_SFT 10 1916#define RT5670_IF1_ADC2_IN1_SFT 10
1917#define RT5670_MCLK_DET (0x1 << 3)
1917 1918
1918/* General Control2 (0xfb) */ 1919/* General Control2 (0xfb) */
1919#define RT5670_RXDC_SRC_MASK (0x1 << 7) 1920#define RT5670_RXDC_SRC_MASK (0x1 << 7)
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 91879ea95415..ebd0f7c5ad3b 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -20,7 +20,6 @@
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/gpio.h> 21#include <linux/gpio.h>
22#include <linux/sched.h> 22#include <linux/sched.h>
23#include <linux/kthread.h>
24#include <linux/uaccess.h> 23#include <linux/uaccess.h>
25#include <linux/miscdevice.h> 24#include <linux/miscdevice.h>
26#include <linux/regulator/consumer.h> 25#include <linux/regulator/consumer.h>
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 1cb39309f5d5..cf026252cd4a 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * simple-card-core.c 2 * simple-card-utils.c
3 * 3 *
4 * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 4 * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5 * 5 *
@@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
195 195
196int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) 196int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
197{ 197{
198 if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
199 return -EINVAL;
200
201 /* Assumes platform == cpu */ 198 /* Assumes platform == cpu */
202 if (!dai_link->platform_of_node) 199 if (!dai_link->platform_of_node)
203 dai_link->platform_of_node = dai_link->cpu_of_node; 200 dai_link->platform_of_node = dai_link->cpu_of_node;
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index fe3d3ca45b39..bb86ee042490 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -22,7 +22,7 @@
22#include <sound/soc-dai.h> 22#include <sound/soc-dai.h>
23#include <sound/simple_card_utils.h> 23#include <sound/simple_card_utils.h>
24 24
25struct asoc_simple_card_priv { 25struct simple_card_data {
26 struct snd_soc_card snd_card; 26 struct snd_soc_card snd_card;
27 struct snd_soc_codec_conf codec_conf; 27 struct snd_soc_codec_conf codec_conf;
28 struct asoc_simple_dai *dai_props; 28 struct asoc_simple_dai *dai_props;
@@ -42,7 +42,7 @@ struct asoc_simple_card_priv {
42static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 42static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
43{ 43{
44 struct snd_soc_pcm_runtime *rtd = substream->private_data; 44 struct snd_soc_pcm_runtime *rtd = substream->private_data;
45 struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); 45 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
46 struct asoc_simple_dai *dai_props = 46 struct asoc_simple_dai *dai_props =
47 simple_priv_to_props(priv, rtd->num); 47 simple_priv_to_props(priv, rtd->num);
48 48
@@ -52,7 +52,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
52static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 52static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
53{ 53{
54 struct snd_soc_pcm_runtime *rtd = substream->private_data; 54 struct snd_soc_pcm_runtime *rtd = substream->private_data;
55 struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); 55 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
56 struct asoc_simple_dai *dai_props = 56 struct asoc_simple_dai *dai_props =
57 simple_priv_to_props(priv, rtd->num); 57 simple_priv_to_props(priv, rtd->num);
58 58
@@ -66,7 +66,7 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
66 66
67static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 67static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
68{ 68{
69 struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); 69 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
70 struct snd_soc_dai *dai; 70 struct snd_soc_dai *dai;
71 struct snd_soc_dai_link *dai_link; 71 struct snd_soc_dai_link *dai_link;
72 struct asoc_simple_dai *dai_props; 72 struct asoc_simple_dai *dai_props;
@@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
84static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 84static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
85 struct snd_pcm_hw_params *params) 85 struct snd_pcm_hw_params *params)
86{ 86{
87 struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); 87 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
88 struct snd_interval *rate = hw_param_interval(params, 88 struct snd_interval *rate = hw_param_interval(params,
89 SNDRV_PCM_HW_PARAM_RATE); 89 SNDRV_PCM_HW_PARAM_RATE);
90 struct snd_interval *channels = hw_param_interval(params, 90 struct snd_interval *channels = hw_param_interval(params,
@@ -101,8 +101,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
101 return 0; 101 return 0;
102} 102}
103 103
104static int asoc_simple_card_parse_links(struct device_node *np, 104static int asoc_simple_card_dai_link_of(struct device_node *np,
105 struct asoc_simple_card_priv *priv, 105 struct simple_card_data *priv,
106 unsigned int daifmt, 106 unsigned int daifmt,
107 int idx, bool is_fe) 107 int idx, bool is_fe)
108{ 108{
@@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np,
195 return 0; 195 return 0;
196} 196}
197 197
198static int asoc_simple_card_dai_link_of(struct device_node *node, 198static int asoc_simple_card_parse_of(struct device_node *node,
199 struct asoc_simple_card_priv *priv) 199 struct simple_card_data *priv)
200
200{ 201{
201 struct device *dev = simple_priv_to_dev(priv); 202 struct device *dev = simple_priv_to_dev(priv);
202 struct device_node *np; 203 struct device_node *np;
203 unsigned int daifmt = 0; 204 unsigned int daifmt = 0;
204 int ret, i;
205 bool is_fe; 205 bool is_fe;
206 int ret, i;
207
208 if (!node)
209 return -EINVAL;
210
211 ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing");
212 if (ret < 0)
213 return ret;
214
215 /* sampling rate convert */
216 of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
217
218 /* channels transfer */
219 of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
206 220
207 /* find 1st codec */ 221 /* find 1st codec */
208 np = of_get_child_by_name(node, PREFIX "codec"); 222 np = of_get_child_by_name(node, PREFIX "codec");
209 if (!np) 223 if (!np)
210 return -ENODEV; 224 return -ENODEV;
211 225
212 ret = asoc_simple_card_parse_daifmt(dev, node, np, 226 ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
213 PREFIX, &daifmt);
214 if (ret < 0) 227 if (ret < 0)
215 return ret; 228 return ret;
216 229
@@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
220 if (strcmp(np->name, PREFIX "cpu") == 0) 233 if (strcmp(np->name, PREFIX "cpu") == 0)
221 is_fe = true; 234 is_fe = true;
222 235
223 ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); 236 ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
224 if (ret < 0) 237 if (ret < 0)
225 return ret; 238 return ret;
226 i++; 239 i++;
227 } 240 }
228 241
229 return 0;
230}
231
232static int asoc_simple_card_parse_of(struct device_node *node,
233 struct asoc_simple_card_priv *priv,
234 struct device *dev)
235{
236 struct asoc_simple_dai *props;
237 struct snd_soc_dai_link *links;
238 int ret;
239 int num;
240
241 if (!node)
242 return -EINVAL;
243
244 num = of_get_child_count(node);
245 props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
246 links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
247 if (!props || !links)
248 return -ENOMEM;
249
250 priv->dai_props = props;
251 priv->dai_link = links;
252
253 /* Init snd_soc_card */
254 priv->snd_card.owner = THIS_MODULE;
255 priv->snd_card.dev = dev;
256 priv->snd_card.dai_link = priv->dai_link;
257 priv->snd_card.num_links = num;
258 priv->snd_card.codec_conf = &priv->codec_conf;
259 priv->snd_card.num_configs = 1;
260
261 ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing");
262 if (ret < 0)
263 return ret;
264
265 /* sampling rate convert */
266 of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
267
268 /* channels transfer */
269 of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
270
271 ret = asoc_simple_card_dai_link_of(node, priv);
272 if (ret < 0)
273 return ret;
274
275 ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); 242 ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
276 if (ret < 0) 243 if (ret < 0)
277 return ret; 244 return ret;
@@ -286,17 +253,37 @@ static int asoc_simple_card_parse_of(struct device_node *node,
286 253
287static int asoc_simple_card_probe(struct platform_device *pdev) 254static int asoc_simple_card_probe(struct platform_device *pdev)
288{ 255{
289 struct asoc_simple_card_priv *priv; 256 struct simple_card_data *priv;
290 struct device_node *np = pdev->dev.of_node; 257 struct snd_soc_dai_link *dai_link;
258 struct asoc_simple_dai *dai_props;
291 struct device *dev = &pdev->dev; 259 struct device *dev = &pdev->dev;
292 int ret; 260 struct device_node *np = pdev->dev.of_node;
261 int num, ret;
293 262
294 /* Allocate the private data */ 263 /* Allocate the private data */
295 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 264 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
296 if (!priv) 265 if (!priv)
297 return -ENOMEM; 266 return -ENOMEM;
298 267
299 ret = asoc_simple_card_parse_of(np, priv, dev); 268 num = of_get_child_count(np);
269
270 dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
271 dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
272 if (!dai_props || !dai_link)
273 return -ENOMEM;
274
275 priv->dai_props = dai_props;
276 priv->dai_link = dai_link;
277
278 /* Init snd_soc_card */
279 priv->snd_card.owner = THIS_MODULE;
280 priv->snd_card.dev = dev;
281 priv->snd_card.dai_link = priv->dai_link;
282 priv->snd_card.num_links = num;
283 priv->snd_card.codec_conf = &priv->codec_conf;
284 priv->snd_card.num_configs = 1;
285
286 ret = asoc_simple_card_parse_of(np, priv);
300 if (ret < 0) { 287 if (ret < 0) {
301 if (ret != -EPROBE_DEFER) 288 if (ret != -EPROBE_DEFER)
302 dev_err(dev, "parse error %d\n", ret); 289 dev_err(dev, "parse error %d\n", ret);
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index f6023b46c107..7c423151ef7d 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,7 @@
1menuconfig SND_SOC_SAMSUNG 1menuconfig SND_SOC_SAMSUNG
2 tristate "ASoC support for Samsung" 2 tristate "ASoC support for Samsung"
3 depends on (PLAT_SAMSUNG || ARCH_EXYNOS) 3 depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
4 depends on COMMON_CLK
4 select SND_SOC_GENERIC_DMAENGINE_PCM 5 select SND_SOC_GENERIC_DMAENGINE_PCM
5 ---help--- 6 ---help---
6 Say Y or M if you want to add support for codecs attached to 7 Say Y or M if you want to add support for codecs attached to
@@ -22,10 +23,6 @@ config SND_S3C2412_SOC_I2S
22config SND_SAMSUNG_PCM 23config SND_SAMSUNG_PCM
23 tristate "Samsung PCM interface support" 24 tristate "Samsung PCM interface support"
24 25
25config SND_SAMSUNG_AC97
26 tristate
27 select SND_SOC_AC97_BUS
28
29config SND_SAMSUNG_SPDIF 26config SND_SAMSUNG_SPDIF
30 tristate "Samsung SPDIF transmitter support" 27 tristate "Samsung SPDIF transmitter support"
31 select SND_SOC_SPDIF 28 select SND_SOC_SPDIF
@@ -53,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
53 50
54config SND_SOC_SAMSUNG_SMDK_WM8580 51config SND_SOC_SAMSUNG_SMDK_WM8580
55 tristate "SoC I2S Audio support for WM8580 on SMDK" 52 tristate "SoC I2S Audio support for WM8580 on SMDK"
56 depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 53 depends on MACH_SMDK6410 || COMPILE_TEST
57 depends on I2C 54 depends on I2C
58 select SND_SOC_WM8580 55 select SND_SOC_WM8580
59 select SND_SAMSUNG_I2S 56 select SND_SAMSUNG_I2S
@@ -69,26 +66,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
69 help 66 help
70 Say Y if you want to add support for SoC audio on the SMDKs. 67 Say Y if you want to add support for SoC audio on the SMDKs.
71 68
72config SND_SOC_SAMSUNG_SMDK2443_WM9710
73 tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
74 depends on MACH_SMDK2443
75 select AC97_BUS
76 select SND_SOC_AC97_CODEC
77 select SND_SAMSUNG_AC97
78 help
79 Say Y if you want to add support for SoC audio on smdk2443
80 with the WM9710.
81
82config SND_SOC_SAMSUNG_LN2440SBC_ALC650
83 tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
84 depends on ARCH_S3C24XX
85 select AC97_BUS
86 select SND_SOC_AC97_CODEC
87 select SND_SAMSUNG_AC97
88 help
89 Say Y if you want to add support for SoC audio on ln2440sbc
90 with the ALC650.
91
92config SND_SOC_SAMSUNG_S3C24XX_UDA134X 69config SND_SOC_SAMSUNG_S3C24XX_UDA134X
93 tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" 70 tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
94 depends on ARCH_S3C24XX 71 depends on ARCH_S3C24XX
@@ -131,17 +108,10 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
131 help 108 help
132 This driver provides audio support for HP iPAQ RX1950 PDA. 109 This driver provides audio support for HP iPAQ RX1950 PDA.
133 110
134config SND_SOC_SAMSUNG_SMDK_WM9713
135 tristate "SoC AC97 Audio support for SMDK with WM9713"
136 depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
137 select SND_SOC_WM9713
138 select SND_SAMSUNG_AC97
139 help
140 Say Y if you want to add support for SoC audio on the SMDK.
141
142config SND_SOC_SMARTQ 111config SND_SOC_SMARTQ
143 tristate "SoC I2S Audio support for SmartQ board" 112 tristate "SoC I2S Audio support for SmartQ board"
144 depends on MACH_SMARTQ && I2C 113 depends on MACH_SMARTQ || COMPILE_TEST
114 depends on I2C
145 select SND_SAMSUNG_I2S 115 select SND_SAMSUNG_I2S
146 select SND_SOC_WM8750 116 select SND_SOC_WM8750
147 117
@@ -151,15 +121,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
151 help 121 help
152 Say Y if you want to add support for SoC S/PDIF audio on the SMDK. 122 Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
153 123
154config SND_SOC_SMDK_WM8580_PCM
155 tristate "SoC PCM Audio support for WM8580 on SMDK"
156 depends on MACH_SMDKV210 || MACH_SMDKC110
157 depends on I2C
158 select SND_SOC_WM8580
159 select SND_SAMSUNG_PCM
160 help
161 Say Y if you want to add support for SoC audio on the SMDK.
162
163config SND_SOC_SMDK_WM8994_PCM 124config SND_SOC_SMDK_WM8994_PCM
164 tristate "SoC PCM Audio support for WM8994 on SMDK" 125 tristate "SoC PCM Audio support for WM8994 on SMDK"
165 depends on I2C=y 126 depends on I2C=y
@@ -229,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631
229 select SND_SAMSUNG_I2S 190 select SND_SAMSUNG_I2S
230 select SND_SOC_RT5631 191 select SND_SOC_RT5631
231 192
193config SND_SOC_SAMSUNG_TM2_WM5110
194 tristate "SoC I2S Audio support for WM5110 on TM2 board"
195 depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
196 select SND_SOC_MAX98504
197 select SND_SOC_WM5110
198 select SND_SAMSUNG_I2S
199 help
200 Say Y if you want to add support for SoC audio on the TM2 board.
201
232endif #SND_SOC_SAMSUNG 202endif #SND_SOC_SAMSUNG
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 5d03f5ce6916..b5df5e2e3d94 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o
3snd-soc-idma-objs := idma.o 3snd-soc-idma-objs := idma.o
4snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o 4snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
5snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o 5snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
6snd-soc-ac97-objs := ac97.o
7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o 6snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
8snd-soc-samsung-spdif-objs := spdif.o 7snd-soc-samsung-spdif-objs := spdif.o
9snd-soc-pcm-objs := pcm.o 8snd-soc-pcm-objs := pcm.o
@@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o
11 10
12obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o 11obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o
13obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o 12obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
14obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
15obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o 13obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
16obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o 14obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
17obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o 15obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
@@ -36,7 +34,6 @@ snd-soc-snow-objs := snow.o
36snd-soc-smdk-wm9713-objs := smdk_wm9713.o 34snd-soc-smdk-wm9713-objs := smdk_wm9713.o
37snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o 35snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
38snd-soc-smdk-spdif-objs := smdk_spdif.o 36snd-soc-smdk-spdif-objs := smdk_spdif.o
39snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
40snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o 37snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
41snd-soc-speyside-objs := speyside.o 38snd-soc-speyside-objs := speyside.o
42snd-soc-tobermory-objs := tobermory.o 39snd-soc-tobermory-objs := tobermory.o
@@ -44,11 +41,10 @@ snd-soc-lowland-objs := lowland.o
44snd-soc-littlemill-objs := littlemill.o 41snd-soc-littlemill-objs := littlemill.o
45snd-soc-bells-objs := bells.o 42snd-soc-bells-objs := bells.o
46snd-soc-arndale-rt5631-objs := arndale_rt5631.o 43snd-soc-arndale-rt5631-objs := arndale_rt5631.o
44snd-soc-tm2-wm5110-objs := tm2_wm5110.o
47 45
48obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o 46obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
49obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 47obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
50obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
51obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
52obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o 48obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
53obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o 49obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
54obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o 50obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
@@ -58,10 +54,8 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
58obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o 54obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
59obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o 55obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
60obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o 56obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
61obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
62obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o 57obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
63obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o 58obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
64obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
65obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o 59obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
66obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o 60obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
67obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o 61obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
@@ -69,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
69obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o 63obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
70obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o 64obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
71obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o 65obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
66obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
deleted file mode 100644
index cbc0023c2bc8..000000000000
--- a/sound/soc/samsung/ac97.c
+++ /dev/null
@@ -1,437 +0,0 @@
1/* sound/soc/samsung/ac97.c
2 *
3 * ALSA SoC Audio Layer - S3C AC97 Controller driver
4 * Evolved from s3c2443-ac97.c
5 *
6 * Copyright (c) 2010 Samsung Electronics Co. Ltd
7 * Author: Jaswinder Singh <jassisinghbrar@gmail.com>
8 * Credits: Graeme Gregory, Sean Choi
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/io.h>
16#include <linux/delay.h>
17#include <linux/clk.h>
18#include <linux/module.h>
19
20#include <sound/soc.h>
21
22#include "regs-ac97.h"
23#include <linux/platform_data/asoc-s3c.h>
24
25#include "dma.h"
26
27#define AC_CMD_ADDR(x) (x << 16)
28#define AC_CMD_DATA(x) (x & 0xffff)
29
30#define S3C_AC97_DAI_PCM 0
31#define S3C_AC97_DAI_MIC 1
32
33struct s3c_ac97_info {
34 struct clk *ac97_clk;
35 void __iomem *regs;
36 struct mutex lock;
37 struct completion done;
38};
39static struct s3c_ac97_info s3c_ac97;
40
41static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = {
42 .addr_width = 4,
43};
44
45static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = {
46 .addr_width = 4,
47};
48
49static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = {
50 .addr_width = 4,
51};
52
53static void s3c_ac97_activate(struct snd_ac97 *ac97)
54{
55 u32 ac_glbctrl, stat;
56
57 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
58 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
59 return; /* Return if already active */
60
61 reinit_completion(&s3c_ac97.done);
62
63 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
64 ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
65 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
66 msleep(1);
67
68 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
69 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
70 msleep(1);
71
72 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
73 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
74 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
75
76 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
77 pr_err("AC97: Unable to activate!\n");
78}
79
80static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
81 unsigned short reg)
82{
83 u32 ac_glbctrl, ac_codec_cmd;
84 u32 stat, addr, data;
85
86 mutex_lock(&s3c_ac97.lock);
87
88 s3c_ac97_activate(ac97);
89
90 reinit_completion(&s3c_ac97.done);
91
92 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
93 ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
94 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
95
96 udelay(50);
97
98 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
99 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
100 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
101
102 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
103 pr_err("AC97: Unable to read!\n");
104
105 stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
106 addr = (stat >> 16) & 0x7f;
107 data = (stat & 0xffff);
108
109 if (addr != reg)
110 pr_err("ac97: req addr = %02x, rep addr = %02x\n",
111 reg, addr);
112
113 mutex_unlock(&s3c_ac97.lock);
114
115 return (unsigned short)data;
116}
117
118static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
119 unsigned short val)
120{
121 u32 ac_glbctrl, ac_codec_cmd;
122
123 mutex_lock(&s3c_ac97.lock);
124
125 s3c_ac97_activate(ac97);
126
127 reinit_completion(&s3c_ac97.done);
128
129 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
130 ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
131 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
132
133 udelay(50);
134
135 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
136 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
137 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
138
139 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
140 pr_err("AC97: Unable to write!\n");
141
142 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
143 ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
144 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
145
146 mutex_unlock(&s3c_ac97.lock);
147}
148
149static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
150{
151 pr_debug("AC97: Cold reset\n");
152 writel(S3C_AC97_GLBCTRL_COLDRESET,
153 s3c_ac97.regs + S3C_AC97_GLBCTRL);
154 msleep(1);
155
156 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
157 msleep(1);
158}
159
160static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
161{
162 u32 stat;
163
164 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
165 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
166 return; /* Return if already active */
167
168 pr_debug("AC97: Warm reset\n");
169
170 writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
171 msleep(1);
172
173 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
174 msleep(1);
175
176 s3c_ac97_activate(ac97);
177}
178
179static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
180{
181 u32 ac_glbctrl, ac_glbstat;
182
183 ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
184
185 if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
186
187 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
188 ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
189 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
190
191 complete(&s3c_ac97.done);
192 }
193
194 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
195 ac_glbctrl |= (1<<30); /* Clear interrupt */
196 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
197
198 return IRQ_HANDLED;
199}
200
201static struct snd_ac97_bus_ops s3c_ac97_ops = {
202 .read = s3c_ac97_read,
203 .write = s3c_ac97_write,
204 .warm_reset = s3c_ac97_warm_reset,
205 .reset = s3c_ac97_cold_reset,
206};
207
208static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
209 struct snd_soc_dai *dai)
210{
211 u32 ac_glbctrl;
212
213 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
214 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
215 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
216 else
217 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
218
219 switch (cmd) {
220 case SNDRV_PCM_TRIGGER_START:
221 case SNDRV_PCM_TRIGGER_RESUME:
222 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
223 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
224 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
225 else
226 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
227 break;
228
229 case SNDRV_PCM_TRIGGER_STOP:
230 case SNDRV_PCM_TRIGGER_SUSPEND:
231 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
232 break;
233 }
234
235 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
236
237 return 0;
238}
239
240static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
241 int cmd, struct snd_soc_dai *dai)
242{
243 u32 ac_glbctrl;
244
245 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
246 ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
247
248 switch (cmd) {
249 case SNDRV_PCM_TRIGGER_START:
250 case SNDRV_PCM_TRIGGER_RESUME:
251 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
252 ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
253 break;
254
255 case SNDRV_PCM_TRIGGER_STOP:
256 case SNDRV_PCM_TRIGGER_SUSPEND:
257 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
258 break;
259 }
260
261 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
262
263 return 0;
264}
265
266static const struct snd_soc_dai_ops s3c_ac97_dai_ops = {
267 .trigger = s3c_ac97_trigger,
268};
269
270static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
271 .trigger = s3c_ac97_mic_trigger,
272};
273
274static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
275{
276 snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
277
278 return 0;
279}
280
281static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
282{
283 snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
284
285 return 0;
286}
287
288static struct snd_soc_dai_driver s3c_ac97_dai[] = {
289 [S3C_AC97_DAI_PCM] = {
290 .name = "samsung-ac97",
291 .bus_control = true,
292 .playback = {
293 .stream_name = "AC97 Playback",
294 .channels_min = 2,
295 .channels_max = 2,
296 .rates = SNDRV_PCM_RATE_8000_48000,
297 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
298 .capture = {
299 .stream_name = "AC97 Capture",
300 .channels_min = 2,
301 .channels_max = 2,
302 .rates = SNDRV_PCM_RATE_8000_48000,
303 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
304 .probe = s3c_ac97_dai_probe,
305 .ops = &s3c_ac97_dai_ops,
306 },
307 [S3C_AC97_DAI_MIC] = {
308 .name = "samsung-ac97-mic",
309 .bus_control = true,
310 .capture = {
311 .stream_name = "AC97 Mic Capture",
312 .channels_min = 1,
313 .channels_max = 1,
314 .rates = SNDRV_PCM_RATE_8000_48000,
315 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
316 .probe = s3c_ac97_mic_dai_probe,
317 .ops = &s3c_ac97_mic_dai_ops,
318 },
319};
320
321static const struct snd_soc_component_driver s3c_ac97_component = {
322 .name = "s3c-ac97",
323};
324
325static int s3c_ac97_probe(struct platform_device *pdev)
326{
327 struct resource *mem_res, *irq_res;
328 struct s3c_audio_pdata *ac97_pdata;
329 int ret;
330
331 ac97_pdata = pdev->dev.platform_data;
332 if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
333 dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
334 return -EINVAL;
335 }
336
337 /* Check for availability of necessary resource */
338 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
339 if (!irq_res) {
340 dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
341 return -ENXIO;
342 }
343
344 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
345 s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
346 if (IS_ERR(s3c_ac97.regs))
347 return PTR_ERR(s3c_ac97.regs);
348
349 s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback;
350 s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA;
351 s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture;
352 s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA;
353 s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic;
354 s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA;
355
356 init_completion(&s3c_ac97.done);
357 mutex_init(&s3c_ac97.lock);
358
359 s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97");
360 if (IS_ERR(s3c_ac97.ac97_clk)) {
361 dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
362 ret = -ENODEV;
363 goto err2;
364 }
365 clk_prepare_enable(s3c_ac97.ac97_clk);
366
367 if (ac97_pdata->cfg_gpio(pdev)) {
368 dev_err(&pdev->dev, "Unable to configure gpio\n");
369 ret = -EINVAL;
370 goto err3;
371 }
372
373 ret = request_irq(irq_res->start, s3c_ac97_irq,
374 0, "AC97", NULL);
375 if (ret < 0) {
376 dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
377 goto err4;
378 }
379
380 ret = snd_soc_set_ac97_ops(&s3c_ac97_ops);
381 if (ret != 0) {
382 dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
383 goto err4;
384 }
385
386 ret = samsung_asoc_dma_platform_register(&pdev->dev,
387 ac97_pdata->dma_filter,
388 NULL, NULL);
389 if (ret) {
390 dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
391 goto err5;
392 }
393
394 ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
395 s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
396 if (ret)
397 goto err5;
398
399 return 0;
400err5:
401 free_irq(irq_res->start, NULL);
402err4:
403err3:
404 clk_disable_unprepare(s3c_ac97.ac97_clk);
405err2:
406 snd_soc_set_ac97_ops(NULL);
407 return ret;
408}
409
410static int s3c_ac97_remove(struct platform_device *pdev)
411{
412 struct resource *irq_res;
413
414 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
415 if (irq_res)
416 free_irq(irq_res->start, NULL);
417
418 clk_disable_unprepare(s3c_ac97.ac97_clk);
419 snd_soc_set_ac97_ops(NULL);
420
421 return 0;
422}
423
424static struct platform_driver s3c_ac97_driver = {
425 .probe = s3c_ac97_probe,
426 .remove = s3c_ac97_remove,
427 .driver = {
428 .name = "samsung-ac97",
429 },
430};
431
432module_platform_driver(s3c_ac97_driver);
433
434MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
435MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
436MODULE_LICENSE("GPL");
437MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 8766ebb0dc9b..e00974bc5616 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
1029static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) 1029static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
1030{ 1030{
1031 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); 1031 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
1032 unsigned long flags;
1032 1033
1033 if (!is_secondary(i2s)) { 1034 if (!is_secondary(i2s)) {
1034 if (i2s->quirks & QUIRK_NEED_RSTCLR) { 1035 if (i2s->quirks & QUIRK_NEED_RSTCLR) {
1035 spin_lock(i2s->lock); 1036 spin_lock_irqsave(i2s->lock, flags);
1036 writel(0, i2s->addr + I2SCON); 1037 writel(0, i2s->addr + I2SCON);
1037 spin_unlock(i2s->lock); 1038 spin_unlock_irqrestore(i2s->lock, flags);
1038 } 1039 }
1039 } 1040 }
1040 1041
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
deleted file mode 100644
index 9342fc270c2b..000000000000
--- a/sound/soc/samsung/ln2440sbc_alc650.c
+++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 * SoC audio for ln2440sbc
3 *
4 * Copyright 2007 KonekTel, a.s.
5 * Author: Ivan Kuten
6 * ivan.kuten@promwad.com
7 *
8 * Heavily based on smdk2443_wm9710.c
9 * Copyright 2007 Wolfson Microelectronics PLC.
10 * Author: Graeme Gregory
11 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 *
17 */
18
19#include <linux/module.h>
20#include <sound/soc.h>
21
22static struct snd_soc_card ln2440sbc;
23
24static struct snd_soc_dai_link ln2440sbc_dai[] = {
25{
26 .name = "AC97",
27 .stream_name = "AC97 HiFi",
28 .cpu_dai_name = "samsung-ac97",
29 .codec_dai_name = "ac97-hifi",
30 .codec_name = "ac97-codec",
31 .platform_name = "samsung-ac97",
32},
33};
34
35static struct snd_soc_card ln2440sbc = {
36 .name = "LN2440SBC",
37 .owner = THIS_MODULE,
38 .dai_link = ln2440sbc_dai,
39 .num_links = ARRAY_SIZE(ln2440sbc_dai),
40};
41
42static struct platform_device *ln2440sbc_snd_ac97_device;
43
44static int __init ln2440sbc_init(void)
45{
46 int ret;
47
48 ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
49 if (!ln2440sbc_snd_ac97_device)
50 return -ENOMEM;
51
52 platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
53 ret = platform_device_add(ln2440sbc_snd_ac97_device);
54
55 if (ret)
56 platform_device_put(ln2440sbc_snd_ac97_device);
57
58 return ret;
59}
60
61static void __exit ln2440sbc_exit(void)
62{
63 platform_device_unregister(ln2440sbc_snd_ac97_device);
64}
65
66module_init(ln2440sbc_init);
67module_exit(ln2440sbc_exit);
68
69/* Module information */
70MODULE_AUTHOR("Ivan Kuten");
71MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
72MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index c484985812ed..d50a6377c23d 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
499 499
500 pcm_pdata = pdev->dev.platform_data; 500 pcm_pdata = pdev->dev.platform_data;
501 501
502 /* Check for availability of necessary resource */
503 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
504 if (!mem_res) {
505 dev_err(&pdev->dev, "Unable to get register resource\n");
506 return -ENXIO;
507 }
508
509 if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { 502 if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
510 dev_err(&pdev->dev, "Unable to configure gpio\n"); 503 dev_err(&pdev->dev, "Unable to configure gpio\n");
511 return -EINVAL; 504 return -EINVAL;
@@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
519 /* Default is 128fs */ 512 /* Default is 128fs */
520 pcm->sclk_per_fs = 128; 513 pcm->sclk_per_fs = 128;
521 514
515 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
516 pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res);
517 if (IS_ERR(pcm->regs))
518 return PTR_ERR(pcm->regs);
519
522 pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus"); 520 pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");
523 if (IS_ERR(pcm->cclk)) { 521 if (IS_ERR(pcm->cclk)) {
524 dev_err(&pdev->dev, "failed to get audio-bus\n"); 522 dev_err(&pdev->dev, "failed to get audio-bus clock\n");
525 ret = PTR_ERR(pcm->cclk); 523 return PTR_ERR(pcm->cclk);
526 goto err1;
527 } 524 }
528 clk_prepare_enable(pcm->cclk); 525 clk_prepare_enable(pcm->cclk);
529 526
530 /* record our pcm structure for later use in the callbacks */ 527 /* record our pcm structure for later use in the callbacks */
531 dev_set_drvdata(&pdev->dev, pcm); 528 dev_set_drvdata(&pdev->dev, pcm);
532 529
533 if (!request_mem_region(mem_res->start,
534 resource_size(mem_res), "samsung-pcm")) {
535 dev_err(&pdev->dev, "Unable to request register region\n");
536 ret = -EBUSY;
537 goto err2;
538 }
539
540 pcm->regs = ioremap(mem_res->start, 0x100);
541 if (pcm->regs == NULL) {
542 dev_err(&pdev->dev, "cannot ioremap registers\n");
543 ret = -ENXIO;
544 goto err3;
545 }
546
547 pcm->pclk = devm_clk_get(&pdev->dev, "pcm"); 530 pcm->pclk = devm_clk_get(&pdev->dev, "pcm");
548 if (IS_ERR(pcm->pclk)) { 531 if (IS_ERR(pcm->pclk)) {
549 dev_err(&pdev->dev, "failed to get pcm_clock\n"); 532 dev_err(&pdev->dev, "failed to get pcm clock\n");
550 ret = -ENOENT; 533 ret = PTR_ERR(pcm->pclk);
551 goto err4; 534 goto err_dis_cclk;
552 } 535 }
553 clk_prepare_enable(pcm->pclk); 536 clk_prepare_enable(pcm->pclk);
554 537
@@ -569,7 +552,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
569 NULL, NULL); 552 NULL, NULL);
570 if (ret) { 553 if (ret) {
571 dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); 554 dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
572 goto err5; 555 goto err_dis_pclk;
573 } 556 }
574 557
575 pm_runtime_enable(&pdev->dev); 558 pm_runtime_enable(&pdev->dev);
@@ -578,36 +561,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
578 &s3c_pcm_dai[pdev->id], 1); 561 &s3c_pcm_dai[pdev->id], 1);
579 if (ret != 0) { 562 if (ret != 0) {
580 dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); 563 dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
581 goto err6; 564 goto err_dis_pm;
582 } 565 }
583 566
584 return 0; 567 return 0;
585err6: 568
569err_dis_pm:
586 pm_runtime_disable(&pdev->dev); 570 pm_runtime_disable(&pdev->dev);
587err5: 571err_dis_pclk:
588 clk_disable_unprepare(pcm->pclk); 572 clk_disable_unprepare(pcm->pclk);
589err4: 573err_dis_cclk:
590 iounmap(pcm->regs);
591err3:
592 release_mem_region(mem_res->start, resource_size(mem_res));
593err2:
594 clk_disable_unprepare(pcm->cclk); 574 clk_disable_unprepare(pcm->cclk);
595err1:
596 return ret; 575 return ret;
597} 576}
598 577
599static int s3c_pcm_dev_remove(struct platform_device *pdev) 578static int s3c_pcm_dev_remove(struct platform_device *pdev)
600{ 579{
601 struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; 580 struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
602 struct resource *mem_res;
603 581
604 pm_runtime_disable(&pdev->dev); 582 pm_runtime_disable(&pdev->dev);
605
606 iounmap(pcm->regs);
607
608 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
609 release_mem_region(mem_res->start, resource_size(mem_res));
610
611 clk_disable_unprepare(pcm->cclk); 583 clk_disable_unprepare(pcm->cclk);
612 clk_disable_unprepare(pcm->pclk); 584 clk_disable_unprepare(pcm->pclk);
613 585
diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h
deleted file mode 100644
index a71be45bbffc..000000000000
--- a/sound/soc/samsung/regs-ac97.h
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
3 * http://www.simtec.co.uk/products/SWLINUX/
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * S3C2440 AC97 Controller
10*/
11
12#ifndef __SAMSUNG_REGS_AC97_H__
13#define __SAMSUNG_REGS_AC97_H__
14
15#define S3C_AC97_GLBCTRL (0x00)
16
17#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22)
18#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21)
19#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20)
20#define S3C_AC97_GLBCTRL_MICINORIE (1<<19)
21#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18)
22#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17)
23#define S3C_AC97_GLBCTRL_MICINTIE (1<<16)
24#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12)
25#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12)
26#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12)
27#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12)
28#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10)
29#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10)
30#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10)
31#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10)
32#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8)
33#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8)
34#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8)
35#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8)
36#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3)
37#define S3C_AC97_GLBCTRL_ACLINKON (1<<2)
38#define S3C_AC97_GLBCTRL_WARMRESET (1<<1)
39#define S3C_AC97_GLBCTRL_COLDRESET (1<<0)
40
41#define S3C_AC97_GLBSTAT (0x04)
42
43#define S3C_AC97_GLBSTAT_CODECREADY (1<<22)
44#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21)
45#define S3C_AC97_GLBSTAT_PCMINORI (1<<20)
46#define S3C_AC97_GLBSTAT_MICINORI (1<<19)
47#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18)
48#define S3C_AC97_GLBSTAT_PCMINTI (1<<17)
49#define S3C_AC97_GLBSTAT_MICINTI (1<<16)
50#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0)
51#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0)
52#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0)
53#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0)
54#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0)
55#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0)
56
57#define S3C_AC97_CODEC_CMD (0x08)
58
59#define S3C_AC97_CODEC_CMD_READ (1<<23)
60
61#define S3C_AC97_STAT (0x0c)
62#define S3C_AC97_PCM_ADDR (0x10)
63#define S3C_AC97_PCM_DATA (0x18)
64#define S3C_AC97_MIC_DATA (0x1C)
65
66#endif /* __SAMSUNG_REGS_AC97_H__ */
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 189827760229..07f5091b33e8 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -30,8 +30,6 @@
30#include "dma.h" 30#include "dma.h"
31#include "s3c24xx-i2s.h" 31#include "s3c24xx-i2s.h"
32 32
33#include <linux/platform_data/asoc-s3c.h>
34
35static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { 33static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
36 .addr_width = 2, 34 .addr_width = 2,
37}; 35};
@@ -56,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on)
56 u32 iiscon; 54 u32 iiscon;
57 u32 iismod; 55 u32 iismod;
58 56
59 pr_debug("Entered %s\n", __func__);
60
61 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 57 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
62 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 58 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
63 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 59 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -101,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on)
101 u32 iiscon; 97 u32 iiscon;
102 u32 iismod; 98 u32 iismod;
103 99
104 pr_debug("Entered %s\n", __func__);
105
106 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 100 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
107 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 101 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
108 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 102 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -149,8 +143,6 @@ static int s3c24xx_snd_lrsync(void)
149 u32 iiscon; 143 u32 iiscon;
150 int timeout = 50; /* 5ms */ 144 int timeout = 50; /* 5ms */
151 145
152 pr_debug("Entered %s\n", __func__);
153
154 while (1) { 146 while (1) {
155 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 147 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
156 if (iiscon & S3C2410_IISCON_LRINDEX) 148 if (iiscon & S3C2410_IISCON_LRINDEX)
@@ -169,8 +161,6 @@ static int s3c24xx_snd_lrsync(void)
169 */ 161 */
170static inline int s3c24xx_snd_is_clkmaster(void) 162static inline int s3c24xx_snd_is_clkmaster(void)
171{ 163{
172 pr_debug("Entered %s\n", __func__);
173
174 return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; 164 return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
175} 165}
176 166
@@ -182,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
182{ 172{
183 u32 iismod; 173 u32 iismod;
184 174
185 pr_debug("Entered %s\n", __func__);
186
187 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 175 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
188 pr_debug("hw_params r: IISMOD: %x \n", iismod); 176 pr_debug("hw_params r: IISMOD: %x \n", iismod);
189 177
@@ -211,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
211 199
212 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 200 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
213 pr_debug("hw_params w: IISMOD: %x \n", iismod); 201 pr_debug("hw_params w: IISMOD: %x \n", iismod);
202
214 return 0; 203 return 0;
215} 204}
216 205
@@ -221,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
221 struct snd_dmaengine_dai_dma_data *dma_data; 210 struct snd_dmaengine_dai_dma_data *dma_data;
222 u32 iismod; 211 u32 iismod;
223 212
224 pr_debug("Entered %s\n", __func__);
225
226 dma_data = snd_soc_dai_get_dma_data(dai, substream); 213 dma_data = snd_soc_dai_get_dma_data(dai, substream);
227 214
228 /* Working copies of register */ 215 /* Working copies of register */
@@ -244,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
244 231
245 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 232 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
246 pr_debug("hw_params w: IISMOD: %x\n", iismod); 233 pr_debug("hw_params w: IISMOD: %x\n", iismod);
234
247 return 0; 235 return 0;
248} 236}
249 237
@@ -252,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
252{ 240{
253 int ret = 0; 241 int ret = 0;
254 242
255 pr_debug("Entered %s\n", __func__);
256
257 switch (cmd) { 243 switch (cmd) {
258 case SNDRV_PCM_TRIGGER_START: 244 case SNDRV_PCM_TRIGGER_START:
259 case SNDRV_PCM_TRIGGER_RESUME: 245 case SNDRV_PCM_TRIGGER_RESUME:
@@ -295,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
295{ 281{
296 u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 282 u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
297 283
298 pr_debug("Entered %s\n", __func__);
299
300 iismod &= ~S3C2440_IISMOD_MPLL; 284 iismod &= ~S3C2440_IISMOD_MPLL;
301 285
302 switch (clk_id) { 286 switch (clk_id) {
@@ -321,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
321{ 305{
322 u32 reg; 306 u32 reg;
323 307
324 pr_debug("Entered %s\n", __func__);
325
326 switch (div_id) { 308 switch (div_id) {
327 case S3C24XX_DIV_BCLK: 309 case S3C24XX_DIV_BCLK:
328 reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; 310 reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
@@ -356,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
356 338
357static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) 339static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
358{ 340{
359 pr_debug("Entered %s\n", __func__);
360
361 snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, 341 snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
362 &s3c24xx_i2s_pcm_stereo_in); 342 &s3c24xx_i2s_pcm_stereo_in);
363 343
@@ -383,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
383#ifdef CONFIG_PM 363#ifdef CONFIG_PM
384static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) 364static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
385{ 365{
386 pr_debug("Entered %s\n", __func__);
387
388 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 366 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
389 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 367 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
390 s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 368 s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -397,7 +375,6 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
397 375
398static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) 376static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
399{ 377{
400 pr_debug("Entered %s\n", __func__);
401 clk_prepare_enable(s3c24xx_i2s.iis_clk); 378 clk_prepare_enable(s3c24xx_i2s.iis_clk);
402 379
403 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); 380 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -412,7 +389,6 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
412#define s3c24xx_i2s_resume NULL 389#define s3c24xx_i2s_resume NULL
413#endif 390#endif
414 391
415
416#define S3C24XX_I2S_RATES \ 392#define S3C24XX_I2S_RATES \
417 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 393 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
418 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 394 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
@@ -449,41 +425,28 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = {
449 425
450static int s3c24xx_iis_dev_probe(struct platform_device *pdev) 426static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
451{ 427{
452 int ret = 0;
453 struct resource *res; 428 struct resource *res;
454 struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); 429 int ret;
455
456 if (!pdata) {
457 dev_err(&pdev->dev, "missing platform data");
458 return -ENXIO;
459 }
460 430
461 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 431 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
462 if (!res) {
463 dev_err(&pdev->dev, "Can't get IO resource.\n");
464 return -ENOENT;
465 }
466 s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); 432 s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
467 if (IS_ERR(s3c24xx_i2s.regs)) 433 if (IS_ERR(s3c24xx_i2s.regs))
468 return PTR_ERR(s3c24xx_i2s.regs); 434 return PTR_ERR(s3c24xx_i2s.regs);
469 435
470 s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; 436 s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO;
471 s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
472 s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; 437 s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
473 s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
474 438
475 ret = samsung_asoc_dma_platform_register(&pdev->dev, 439 ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL,
476 pdata->dma_filter,
477 NULL, NULL); 440 NULL, NULL);
478 if (ret) { 441 if (ret) {
479 pr_err("failed to register the dma: %d\n", ret); 442 dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret);
480 return ret; 443 return ret;
481 } 444 }
482 445
483 ret = devm_snd_soc_register_component(&pdev->dev, 446 ret = devm_snd_soc_register_component(&pdev->dev,
484 &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); 447 &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
485 if (ret) 448 if (ret)
486 pr_err("failed to register the dai\n"); 449 dev_err(&pdev->dev, "Failed to register the DAI\n");
487 450
488 return ret; 451 return ret;
489} 452}
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 7853fbe6ccc9..81a78940967c 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -19,9 +19,15 @@
19#include <sound/s3c24xx_uda134x.h> 19#include <sound/s3c24xx_uda134x.h>
20 20
21#include "regs-iis.h" 21#include "regs-iis.h"
22
23#include "s3c24xx-i2s.h" 22#include "s3c24xx-i2s.h"
24 23
24struct s3c24xx_uda134x {
25 struct clk *xtal;
26 struct clk *pclk;
27 struct mutex clk_lock;
28 int clk_users;
29};
30
25/* #define ENFORCE_RATES 1 */ 31/* #define ENFORCE_RATES 1 */
26/* 32/*
27 Unfortunately the S3C24XX in master mode has a limited capacity of 33 Unfortunately the S3C24XX in master mode has a limited capacity of
@@ -36,15 +42,6 @@
36 possible an error will be returned. 42 possible an error will be returned.
37*/ 43*/
38 44
39static struct clk *xtal;
40static struct clk *pclk;
41/* this is need because we don't have a place where to keep the
42 * pointers to the clocks in each substream. We get the clocks only
43 * when we are actually using them so we don't block stuff like
44 * frequency change or oscillator power-off */
45static int clk_users;
46static DEFINE_MUTEX(clk_lock);
47
48static unsigned int rates[33 * 2]; 45static unsigned int rates[33 * 2];
49#ifdef ENFORCE_RATES 46#ifdef ENFORCE_RATES
50static struct snd_pcm_hw_constraint_list hw_constraints_rates = { 47static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
@@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
57static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) 54static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
58{ 55{
59 struct snd_soc_pcm_runtime *rtd = substream->private_data; 56 struct snd_soc_pcm_runtime *rtd = substream->private_data;
57 struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
60 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 58 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
61#ifdef ENFORCE_RATES
62 struct snd_pcm_runtime *runtime = substream->runtime;
63#endif
64 int ret = 0; 59 int ret = 0;
65 60
66 mutex_lock(&clk_lock); 61 mutex_lock(&priv->clk_lock);
67 62
68 if (clk_users == 0) { 63 if (priv->clk_users == 0) {
69 xtal = clk_get(rtd->dev, "xtal"); 64 priv->xtal = clk_get(rtd->dev, "xtal");
70 if (IS_ERR(xtal)) { 65 if (IS_ERR(priv->xtal)) {
71 dev_err(rtd->dev, "%s cannot get xtal\n", __func__); 66 dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
72 ret = PTR_ERR(xtal); 67 ret = PTR_ERR(priv->xtal);
73 } else { 68 } else {
74 pclk = clk_get(cpu_dai->dev, "iis"); 69 priv->pclk = clk_get(cpu_dai->dev, "iis");
75 if (IS_ERR(pclk)) { 70 if (IS_ERR(priv->pclk)) {
76 dev_err(rtd->dev, "%s cannot get pclk\n", 71 dev_err(rtd->dev, "%s cannot get pclk\n",
77 __func__); 72 __func__);
78 clk_put(xtal); 73 clk_put(priv->xtal);
79 ret = PTR_ERR(pclk); 74 ret = PTR_ERR(priv->pclk);
80 } 75 }
81 } 76 }
82 if (!ret) { 77 if (!ret) {
@@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
85 for (i = 0; i < 2; i++) { 80 for (i = 0; i < 2; i++) {
86 int fs = i ? 256 : 384; 81 int fs = i ? 256 : 384;
87 82
88 rates[i*33] = clk_get_rate(xtal) / fs; 83 rates[i*33] = clk_get_rate(priv->xtal) / fs;
89 for (j = 1; j < 33; j++) 84 for (j = 1; j < 33; j++)
90 rates[i*33 + j] = clk_get_rate(pclk) / 85 rates[i*33 + j] = clk_get_rate(priv->pclk) /
91 (j * fs); 86 (j * fs);
92 } 87 }
93 } 88 }
94 } 89 }
95 clk_users += 1; 90 priv->clk_users += 1;
96 mutex_unlock(&clk_lock); 91 mutex_unlock(&priv->clk_lock);
92
97 if (!ret) { 93 if (!ret) {
98#ifdef ENFORCE_RATES 94#ifdef ENFORCE_RATES
99 ret = snd_pcm_hw_constraint_list(runtime, 0, 95 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
100 SNDRV_PCM_HW_PARAM_RATE, 96 SNDRV_PCM_HW_PARAM_RATE,
101 &hw_constraints_rates); 97 &hw_constraints_rates);
102 if (ret < 0) 98 if (ret < 0)
@@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
109 105
110static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) 106static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
111{ 107{
112 mutex_lock(&clk_lock); 108 struct snd_soc_pcm_runtime *rtd = substream->private_data;
113 clk_users -= 1; 109 struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
114 if (clk_users == 0) { 110
115 clk_put(xtal); 111 mutex_lock(&priv->clk_lock);
116 xtal = NULL; 112 priv->clk_users -= 1;
117 clk_put(pclk); 113 if (priv->clk_users == 0) {
118 pclk = NULL; 114 clk_put(priv->xtal);
115 priv->xtal = NULL;
116 clk_put(priv->pclk);
117 priv->pclk = NULL;
119 } 118 }
120 mutex_unlock(&clk_lock); 119 mutex_unlock(&priv->clk_lock);
121} 120}
122 121
123static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, 122static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
@@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
228static int s3c24xx_uda134x_probe(struct platform_device *pdev) 227static int s3c24xx_uda134x_probe(struct platform_device *pdev)
229{ 228{
230 struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; 229 struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
230 struct s3c24xx_uda134x *priv;
231 int ret; 231 int ret;
232 232
233 platform_set_drvdata(pdev, card); 233 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
234 if (!priv)
235 return -ENOMEM;
236
237 mutex_init(&priv->clk_lock);
238
234 card->dev = &pdev->dev; 239 card->dev = &pdev->dev;
240 platform_set_drvdata(pdev, card);
241 snd_soc_card_set_drvdata(card, priv);
235 242
236 ret = devm_snd_soc_register_card(&pdev->dev, card); 243 ret = devm_snd_soc_register_card(&pdev->dev, card);
237 if (ret) 244 if (ret)
diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c
deleted file mode 100644
index c390aad68cfb..000000000000
--- a/sound/soc/samsung/smdk2443_wm9710.c
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * smdk2443_wm9710.c -- SoC audio for smdk2443
3 *
4 * Copyright 2007 Wolfson Microelectronics PLC.
5 * Author: Graeme Gregory
6 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <sound/soc.h>
17
18static struct snd_soc_card smdk2443;
19
20static struct snd_soc_dai_link smdk2443_dai[] = {
21{
22 .name = "AC97",
23 .stream_name = "AC97 HiFi",
24 .cpu_dai_name = "samsung-ac97",
25 .codec_dai_name = "ac97-hifi",
26 .codec_name = "ac97-codec",
27 .platform_name = "samsung-ac97",
28},
29};
30
31static struct snd_soc_card smdk2443 = {
32 .name = "SMDK2443",
33 .owner = THIS_MODULE,
34 .dai_link = smdk2443_dai,
35 .num_links = ARRAY_SIZE(smdk2443_dai),
36};
37
38static struct platform_device *smdk2443_snd_ac97_device;
39
40static int __init smdk2443_init(void)
41{
42 int ret;
43
44 smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
45 if (!smdk2443_snd_ac97_device)
46 return -ENOMEM;
47
48 platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
49 ret = platform_device_add(smdk2443_snd_ac97_device);
50
51 if (ret)
52 platform_device_put(smdk2443_snd_ac97_device);
53
54 return ret;
55}
56
57static void __exit smdk2443_exit(void)
58{
59 platform_device_unregister(smdk2443_snd_ac97_device);
60}
61
62module_init(smdk2443_init);
63module_exit(smdk2443_exit);
64
65/* Module information */
66MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
67MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
68MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
index 548bfd993788..de724ce7b955 100644
--- a/sound/soc/samsung/smdk_wm8580.c
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -14,8 +14,6 @@
14#include <sound/soc.h> 14#include <sound/soc.h>
15#include <sound/pcm_params.h> 15#include <sound/pcm_params.h>
16 16
17#include <asm/mach-types.h>
18
19#include "../codecs/wm8580.h" 17#include "../codecs/wm8580.h"
20#include "i2s.h" 18#include "i2s.h"
21 19
@@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
147enum { 145enum {
148 PRI_PLAYBACK = 0, 146 PRI_PLAYBACK = 0,
149 PRI_CAPTURE, 147 PRI_CAPTURE,
150 SEC_PLAYBACK,
151}; 148};
152 149
153#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ 150#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
@@ -157,7 +154,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
157 [PRI_PLAYBACK] = { /* Primary Playback i/f */ 154 [PRI_PLAYBACK] = { /* Primary Playback i/f */
158 .name = "WM8580 PAIF RX", 155 .name = "WM8580 PAIF RX",
159 .stream_name = "Playback", 156 .stream_name = "Playback",
160 .cpu_dai_name = "samsung-i2s.0", 157 .cpu_dai_name = "samsung-i2s.2",
161 .codec_dai_name = "wm8580-hifi-playback", 158 .codec_dai_name = "wm8580-hifi-playback",
162 .platform_name = "samsung-i2s.0", 159 .platform_name = "samsung-i2s.0",
163 .codec_name = "wm8580.0-001b", 160 .codec_name = "wm8580.0-001b",
@@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
167 [PRI_CAPTURE] = { /* Primary Capture i/f */ 164 [PRI_CAPTURE] = { /* Primary Capture i/f */
168 .name = "WM8580 PAIF TX", 165 .name = "WM8580 PAIF TX",
169 .stream_name = "Capture", 166 .stream_name = "Capture",
170 .cpu_dai_name = "samsung-i2s.0", 167 .cpu_dai_name = "samsung-i2s.2",
171 .codec_dai_name = "wm8580-hifi-capture", 168 .codec_dai_name = "wm8580-hifi-capture",
172 .platform_name = "samsung-i2s.0", 169 .platform_name = "samsung-i2s.0",
173 .codec_name = "wm8580.0-001b", 170 .codec_name = "wm8580.0-001b",
@@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = {
175 .init = smdk_wm8580_init_paiftx, 172 .init = smdk_wm8580_init_paiftx,
176 .ops = &smdk_ops, 173 .ops = &smdk_ops,
177 }, 174 },
178 [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
179 .name = "Sec_FIFO TX",
180 .stream_name = "Playback",
181 .cpu_dai_name = "samsung-i2s-sec",
182 .codec_dai_name = "wm8580-hifi-playback",
183 .platform_name = "samsung-i2s-sec",
184 .codec_name = "wm8580.0-001b",
185 .dai_fmt = SMDK_DAI_FMT,
186 .ops = &smdk_ops,
187 },
188}; 175};
189 176
190static struct snd_soc_card smdk = { 177static struct snd_soc_card smdk = {
191 .name = "SMDK-I2S", 178 .name = "SMDK-I2S",
192 .owner = THIS_MODULE, 179 .owner = THIS_MODULE,
193 .dai_link = smdk_dai, 180 .dai_link = smdk_dai,
194 .num_links = 2, 181 .num_links = ARRAY_SIZE(smdk_dai),
195 182
196 .dapm_widgets = smdk_wm8580_dapm_widgets, 183 .dapm_widgets = smdk_wm8580_dapm_widgets,
197 .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets), 184 .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets),
@@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device;
204static int __init smdk_audio_init(void) 191static int __init smdk_audio_init(void)
205{ 192{
206 int ret; 193 int ret;
207 char *str;
208
209 if (machine_is_smdkc100()
210 || machine_is_smdkv210() || machine_is_smdkc110()) {
211 smdk.num_links = 3;
212 } else if (machine_is_smdk6410()) {
213 str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
214 str[strlen(str) - 1] = '2';
215 str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
216 str[strlen(str) - 1] = '2';
217 }
218 194
219 smdk_snd_device = platform_device_alloc("soc-audio", -1); 195 smdk_snd_device = platform_device_alloc("soc-audio", -1);
220 if (!smdk_snd_device) 196 if (!smdk_snd_device)
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
deleted file mode 100644
index a6d223310c67..000000000000
--- a/sound/soc/samsung/smdk_wm8580pcm.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 * sound/soc/samsung/smdk_wm8580pcm.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co. Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11#include <linux/module.h>
12#include <sound/soc.h>
13#include <sound/pcm_params.h>
14#include <sound/pcm.h>
15
16#include <asm/mach-types.h>
17
18#include "../codecs/wm8580.h"
19#include "pcm.h"
20
21/*
22 * Board Settings:
23 * o '1' means 'ON'
24 * o '0' means 'OFF'
25 * o 'X' means 'Don't care'
26 *
27 * SMDK6410 Base B/D: CFG1-0000, CFG2-1111
28 * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000
29 */
30
31#define SMDK_WM8580_EXT_OSC 12000000
32#define SMDK_WM8580_EXT_MCLK 4096000
33#define SMDK_WM8580_EXT_VOICE 2048000
34
35static unsigned long mclk_freq;
36static unsigned long xtal_freq;
37
38/*
39 * If MCLK clock directly gets from XTAL, we don't have to use PLL
40 * to make MCLK, but if XTAL clock source connects with other codec
41 * pin (like XTI), we should have to set codec's PLL to make MCLK.
42 * Because Samsung SoC does not support pcmcdclk output like I2S.
43 */
44
45static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream,
46 struct snd_pcm_hw_params *params)
47{
48 struct snd_soc_pcm_runtime *rtd = substream->private_data;
49 struct snd_soc_dai *codec_dai = rtd->codec_dai;
50 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
51 int rfs, ret;
52
53 switch (params_rate(params)) {
54 case 8000:
55 break;
56 default:
57 printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
58 __func__, __LINE__, params_rate(params));
59 return -EINVAL;
60 }
61
62 rfs = mclk_freq / params_rate(params) / 2;
63
64 if (mclk_freq == xtal_freq) {
65 ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
66 mclk_freq, SND_SOC_CLOCK_IN);
67 if (ret < 0)
68 return ret;
69
70 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
71 WM8580_CLKSRC_MCLK);
72 if (ret < 0)
73 return ret;
74 } else {
75 ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
76 mclk_freq, SND_SOC_CLOCK_IN);
77 if (ret < 0)
78 return ret;
79
80 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
81 WM8580_CLKSRC_PLLA);
82 if (ret < 0)
83 return ret;
84
85 ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
86 xtal_freq, mclk_freq);
87 if (ret < 0)
88 return ret;
89 }
90
91 /* Set PCM source clock on CPU */
92 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
93 mclk_freq, SND_SOC_CLOCK_IN);
94 if (ret < 0)
95 return ret;
96
97 /* Set SCLK_DIV for making bclk */
98 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
99 if (ret < 0)
100 return ret;
101
102 return 0;
103}
104
105static struct snd_soc_ops smdk_wm8580_pcm_ops = {
106 .hw_params = smdk_wm8580_pcm_hw_params,
107};
108
109#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \
110 SND_SOC_DAIFMT_CBS_CFS)
111
112static struct snd_soc_dai_link smdk_dai[] = {
113 {
114 .name = "WM8580 PAIF PCM RX",
115 .stream_name = "Playback",
116 .cpu_dai_name = "samsung-pcm.0",
117 .codec_dai_name = "wm8580-hifi-playback",
118 .platform_name = "samsung-audio",
119 .codec_name = "wm8580.0-001b",
120 .dai_fmt = SMDK_DAI_FMT,
121 .ops = &smdk_wm8580_pcm_ops,
122 }, {
123 .name = "WM8580 PAIF PCM TX",
124 .stream_name = "Capture",
125 .cpu_dai_name = "samsung-pcm.0",
126 .codec_dai_name = "wm8580-hifi-capture",
127 .platform_name = "samsung-pcm.0",
128 .codec_name = "wm8580.0-001b",
129 .dai_fmt = SMDK_DAI_FMT,
130 .ops = &smdk_wm8580_pcm_ops,
131 },
132};
133
134static struct snd_soc_card smdk_pcm = {
135 .name = "SMDK-PCM",
136 .owner = THIS_MODULE,
137 .dai_link = smdk_dai,
138 .num_links = 2,
139};
140
141/*
142 * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1)
143 * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4),
144 * 2.0484Mhz, directly with MCLK both Codec and SoC.
145 */
146static int snd_smdk_probe(struct platform_device *pdev)
147{
148 int ret = 0;
149
150 xtal_freq = SMDK_WM8580_EXT_OSC;
151 mclk_freq = SMDK_WM8580_EXT_MCLK;
152
153 if (machine_is_smdkc110() || machine_is_smdkv210())
154 xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
155
156 smdk_pcm.dev = &pdev->dev;
157 ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm);
158 if (ret)
159 dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
160
161 return ret;
162}
163
164static struct platform_driver snd_smdk_driver = {
165 .driver = {
166 .name = "samsung-smdk-pcm",
167 },
168 .probe = snd_smdk_probe,
169};
170
171module_platform_driver(snd_smdk_driver);
172
173MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
174MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
175MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
deleted file mode 100644
index 0d20e4ed27aa..000000000000
--- a/sound/soc/samsung/smdk_wm9713.c
+++ /dev/null
@@ -1,108 +0,0 @@
1/*
2 * smdk_wm9713.c -- SoC audio for SMDK
3 *
4 * Copyright 2010 Samsung Electronics Co. Ltd.
5 * Author: Jaswinder Singh Brar <jassisinghbrar@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <sound/soc.h>
16
17static struct snd_soc_card smdk;
18
19/*
20 * Default CFG switch settings to use this driver:
21 *
22 * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
23 * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
24 * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
25 * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
26 * SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On
27 */
28
29/*
30 Playback (HeadPhone):-
31 $ amixer sset 'Headphone' unmute
32 $ amixer sset 'Right Headphone Out Mux' 'Headphone'
33 $ amixer sset 'Left Headphone Out Mux' 'Headphone'
34 $ amixer sset 'Right HP Mixer PCM' unmute
35 $ amixer sset 'Left HP Mixer PCM' unmute
36
37 Capture (LineIn):-
38 $ amixer sset 'Right Capture Source' 'Line'
39 $ amixer sset 'Left Capture Source' 'Line'
40*/
41
42static struct snd_soc_dai_link smdk_dai = {
43 .name = "AC97",
44 .stream_name = "AC97 PCM",
45 .platform_name = "samsung-ac97",
46 .cpu_dai_name = "samsung-ac97",
47 .codec_dai_name = "wm9713-hifi",
48 .codec_name = "wm9713-codec",
49};
50
51static struct snd_soc_card smdk = {
52 .name = "SMDK WM9713",
53 .owner = THIS_MODULE,
54 .dai_link = &smdk_dai,
55 .num_links = 1,
56};
57
58static struct platform_device *smdk_snd_wm9713_device;
59static struct platform_device *smdk_snd_ac97_device;
60
61static int __init smdk_init(void)
62{
63 int ret;
64
65 smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
66 if (!smdk_snd_wm9713_device)
67 return -ENOMEM;
68
69 ret = platform_device_add(smdk_snd_wm9713_device);
70 if (ret)
71 goto err1;
72
73 smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
74 if (!smdk_snd_ac97_device) {
75 ret = -ENOMEM;
76 goto err2;
77 }
78
79 platform_set_drvdata(smdk_snd_ac97_device, &smdk);
80
81 ret = platform_device_add(smdk_snd_ac97_device);
82 if (ret)
83 goto err3;
84
85 return 0;
86
87err3:
88 platform_device_put(smdk_snd_ac97_device);
89err2:
90 platform_device_del(smdk_snd_wm9713_device);
91err1:
92 platform_device_put(smdk_snd_wm9713_device);
93 return ret;
94}
95
96static void __exit smdk_exit(void)
97{
98 platform_device_unregister(smdk_snd_ac97_device);
99 platform_device_unregister(smdk_snd_wm9713_device);
100}
101
102module_init(smdk_init);
103module_exit(smdk_exit);
104
105/* Module information */
106MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com");
107MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
108MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
new file mode 100644
index 000000000000..5cdf7d19b87f
--- /dev/null
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -0,0 +1,552 @@
1/*
2 * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
3 *
4 * Authors: Inha Song <ideal.song@samsung.com>
5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/clk.h>
14#include <linux/gpio.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19
20#include "i2s.h"
21#include "../codecs/wm5110.h"
22
23/*
24 * The source clock is XCLKOUT with its mux set to the external fixed rate
25 * oscillator (XXTI).
26 */
27#define MCLK_RATE 24000000U
28
29#define TM2_DAI_AIF1 0
30#define TM2_DAI_AIF2 1
31
32struct tm2_machine_priv {
33 struct snd_soc_codec *codec;
34 unsigned int sysclk_rate;
35 struct gpio_desc *gpio_mic_bias;
36};
37
38static int tm2_start_sysclk(struct snd_soc_card *card)
39{
40 struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
41 struct snd_soc_codec *codec = priv->codec;
42 int ret;
43
44 ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
45 ARIZONA_FLL_SRC_MCLK1,
46 MCLK_RATE,
47 priv->sysclk_rate);
48 if (ret < 0) {
49 dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret);
50 return ret;
51 }
52
53 ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
54 ARIZONA_FLL_SRC_MCLK1,
55 MCLK_RATE,
56 priv->sysclk_rate);
57 if (ret < 0) {
58 dev_err(codec->dev, "Failed to start FLL1: %d\n", ret);
59 return ret;
60 }
61
62 ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
63 ARIZONA_CLK_SRC_FLL1,
64 priv->sysclk_rate,
65 SND_SOC_CLOCK_IN);
66 if (ret < 0) {
67 dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret);
68 return ret;
69 }
70
71 return 0;
72}
73
74static int tm2_stop_sysclk(struct snd_soc_card *card)
75{
76 struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
77 struct snd_soc_codec *codec = priv->codec;
78 int ret;
79
80 ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
81 if (ret < 0) {
82 dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret);
83 return ret;
84 }
85
86 ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
87 ARIZONA_CLK_SRC_FLL1, 0, 0);
88 if (ret < 0) {
89 dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
90 return ret;
91 }
92
93 return 0;
94}
95
96static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
97 struct snd_pcm_hw_params *params)
98{
99 struct snd_soc_pcm_runtime *rtd = substream->private_data;
100 struct snd_soc_codec *codec = rtd->codec;
101 struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
102
103 switch (params_rate(params)) {
104 case 4000:
105 case 8000:
106 case 12000:
107 case 16000:
108 case 24000:
109 case 32000:
110 case 48000:
111 case 96000:
112 case 192000:
113 /* Highest possible SYSCLK frequency: 147.456MHz */
114 priv->sysclk_rate = 147456000U;
115 break;
116 case 11025:
117 case 22050:
118 case 44100:
119 case 88200:
120 case 176400:
121 /* Highest possible SYSCLK frequency: 135.4752 MHz */
122 priv->sysclk_rate = 135475200U;
123 break;
124 default:
125 dev_err(codec->dev, "Not supported sample rate: %d\n",
126 params_rate(params));
127 return -EINVAL;
128 }
129
130 return tm2_start_sysclk(rtd->card);
131}
132
133static struct snd_soc_ops tm2_aif1_ops = {
134 .hw_params = tm2_aif1_hw_params,
135};
136
137static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
138 struct snd_pcm_hw_params *params)
139{
140 struct snd_soc_pcm_runtime *rtd = substream->private_data;
141 struct snd_soc_codec *codec = rtd->codec;
142 unsigned int asyncclk_rate;
143 int ret;
144
145 switch (params_rate(params)) {
146 case 8000:
147 case 12000:
148 case 16000:
149 /* Highest possible ASYNCCLK frequency: 49.152MHz */
150 asyncclk_rate = 49152000U;
151 break;
152 case 11025:
153 /* Highest possible ASYNCCLK frequency: 45.1584 MHz */
154 asyncclk_rate = 45158400U;
155 break;
156 default:
157 dev_err(codec->dev, "Not supported sample rate: %d\n",
158 params_rate(params));
159 return -EINVAL;
160 }
161
162 ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK,
163 ARIZONA_FLL_SRC_MCLK1,
164 MCLK_RATE,
165 asyncclk_rate);
166 if (ret < 0) {
167 dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret);
168 return ret;
169 }
170
171 ret = snd_soc_codec_set_pll(codec, WM5110_FLL2,
172 ARIZONA_FLL_SRC_MCLK1,
173 MCLK_RATE,
174 asyncclk_rate);
175 if (ret < 0) {
176 dev_err(codec->dev, "Failed to start FLL2: %d\n", ret);
177 return ret;
178 }
179
180 ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
181 ARIZONA_CLK_SRC_FLL2,
182 asyncclk_rate,
183 SND_SOC_CLOCK_IN);
184 if (ret < 0) {
185 dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret);
186 return ret;
187 }
188
189 return 0;
190}
191
192static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
193{
194 struct snd_soc_pcm_runtime *rtd = substream->private_data;
195 struct snd_soc_codec *codec = rtd->codec;
196 int ret;
197
198 /* disable FLL2 */
199 ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
200 0, 0);
201 if (ret < 0)
202 dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret);
203
204 return ret;
205}
206
207static struct snd_soc_ops tm2_aif2_ops = {
208 .hw_params = tm2_aif2_hw_params,
209 .hw_free = tm2_aif2_hw_free,
210};
211
212static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
213 struct snd_kcontrol *kcontrol, int event)
214{
215 struct snd_soc_card *card = w->dapm->card;
216 struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
217
218 switch (event) {
219 case SND_SOC_DAPM_PRE_PMU:
220 gpiod_set_value_cansleep(priv->gpio_mic_bias, 1);
221 break;
222 case SND_SOC_DAPM_POST_PMD:
223 gpiod_set_value_cansleep(priv->gpio_mic_bias, 0);
224 break;
225 }
226
227 return 0;
228}
229
230static int tm2_set_bias_level(struct snd_soc_card *card,
231 struct snd_soc_dapm_context *dapm,
232 enum snd_soc_bias_level level)
233{
234 struct snd_soc_pcm_runtime *rtd;
235
236 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
237
238 if (dapm->dev != rtd->codec_dai->dev)
239 return 0;
240
241 switch (level) {
242 case SND_SOC_BIAS_STANDBY:
243 if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
244 tm2_start_sysclk(card);
245 break;
246 case SND_SOC_BIAS_OFF:
247 tm2_stop_sysclk(card);
248 break;
249 default:
250 break;
251 }
252
253 return 0;
254}
255
256static struct snd_soc_aux_dev tm2_speaker_amp_dev;
257
258static int tm2_late_probe(struct snd_soc_card *card)
259{
260 struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
261 struct snd_soc_dai_link_component dlc = { 0 };
262 unsigned int ch_map[] = { 0, 1 };
263 struct snd_soc_dai *amp_pdm_dai;
264 struct snd_soc_pcm_runtime *rtd;
265 struct snd_soc_dai *aif1_dai;
266 struct snd_soc_dai *aif2_dai;
267 int ret;
268
269 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
270 aif1_dai = rtd->codec_dai;
271 priv->codec = rtd->codec;
272
273 ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
274 if (ret < 0) {
275 dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret);
276 return ret;
277 }
278
279 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name);
280 aif2_dai = rtd->codec_dai;
281
282 ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
283 if (ret < 0) {
284 dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret);
285 return ret;
286 }
287
288 dlc.of_node = tm2_speaker_amp_dev.codec_of_node;
289 amp_pdm_dai = snd_soc_find_dai(&dlc);
290 if (!amp_pdm_dai)
291 return -ENODEV;
292
293 /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
294 ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map),
295 ch_map, 0, NULL);
296 if (ret < 0)
297 return ret;
298
299 ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16);
300 if (ret < 0)
301 return ret;
302
303 return 0;
304}
305
306static const struct snd_kcontrol_new tm2_controls[] = {
307 SOC_DAPM_PIN_SWITCH("HP"),
308 SOC_DAPM_PIN_SWITCH("SPK"),
309 SOC_DAPM_PIN_SWITCH("RCV"),
310 SOC_DAPM_PIN_SWITCH("VPS"),
311 SOC_DAPM_PIN_SWITCH("HDMI"),
312
313 SOC_DAPM_PIN_SWITCH("Main Mic"),
314 SOC_DAPM_PIN_SWITCH("Sub Mic"),
315 SOC_DAPM_PIN_SWITCH("Third Mic"),
316
317 SOC_DAPM_PIN_SWITCH("Headset Mic"),
318};
319
320const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
321 SND_SOC_DAPM_HP("HP", NULL),
322 SND_SOC_DAPM_SPK("SPK", NULL),
323 SND_SOC_DAPM_SPK("RCV", NULL),
324 SND_SOC_DAPM_LINE("VPS", NULL),
325 SND_SOC_DAPM_LINE("HDMI", NULL),
326
327 SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias),
328 SND_SOC_DAPM_MIC("Sub Mic", NULL),
329 SND_SOC_DAPM_MIC("Third Mic", NULL),
330
331 SND_SOC_DAPM_MIC("Headset Mic", NULL),
332};
333
334static const struct snd_soc_component_driver tm2_component = {
335 .name = "tm2-audio",
336};
337
338static struct snd_soc_dai_driver tm2_ext_dai[] = {
339 {
340 .name = "Voice call",
341 .playback = {
342 .channels_min = 1,
343 .channels_max = 4,
344 .rate_min = 8000,
345 .rate_max = 48000,
346 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
347 SNDRV_PCM_RATE_48000),
348 .formats = SNDRV_PCM_FMTBIT_S16_LE,
349 },
350 .capture = {
351 .channels_min = 1,
352 .channels_max = 4,
353 .rate_min = 8000,
354 .rate_max = 48000,
355 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
356 SNDRV_PCM_RATE_48000),
357 .formats = SNDRV_PCM_FMTBIT_S16_LE,
358 },
359 },
360 {
361 .name = "Bluetooth",
362 .playback = {
363 .channels_min = 1,
364 .channels_max = 4,
365 .rate_min = 8000,
366 .rate_max = 16000,
367 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
368 .formats = SNDRV_PCM_FMTBIT_S16_LE,
369 },
370 .capture = {
371 .channels_min = 1,
372 .channels_max = 2,
373 .rate_min = 8000,
374 .rate_max = 16000,
375 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
376 .formats = SNDRV_PCM_FMTBIT_S16_LE,
377 },
378 },
379};
380
381static struct snd_soc_dai_link tm2_dai_links[] = {
382 {
383 .name = "WM5110 AIF1",
384 .stream_name = "HiFi Primary",
385 .codec_dai_name = "wm5110-aif1",
386 .ops = &tm2_aif1_ops,
387 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
388 SND_SOC_DAIFMT_CBM_CFM,
389 }, {
390 .name = "WM5110 Voice",
391 .stream_name = "Voice call",
392 .codec_dai_name = "wm5110-aif2",
393 .ops = &tm2_aif2_ops,
394 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
395 SND_SOC_DAIFMT_CBM_CFM,
396 .ignore_suspend = 1,
397 }, {
398 .name = "WM5110 BT",
399 .stream_name = "Bluetooth",
400 .codec_dai_name = "wm5110-aif3",
401 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
402 SND_SOC_DAIFMT_CBM_CFM,
403 .ignore_suspend = 1,
404 }
405};
406
407static struct snd_soc_card tm2_card = {
408 .owner = THIS_MODULE,
409
410 .dai_link = tm2_dai_links,
411 .num_links = ARRAY_SIZE(tm2_dai_links),
412 .controls = tm2_controls,
413 .num_controls = ARRAY_SIZE(tm2_controls),
414 .dapm_widgets = tm2_dapm_widgets,
415 .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets),
416 .aux_dev = &tm2_speaker_amp_dev,
417 .num_aux_devs = 1,
418
419 .late_probe = tm2_late_probe,
420 .set_bias_level = tm2_set_bias_level,
421};
422
423static int tm2_probe(struct platform_device *pdev)
424{
425 struct device *dev = &pdev->dev;
426 struct snd_soc_card *card = &tm2_card;
427 struct tm2_machine_priv *priv;
428 struct device_node *cpu_dai_node, *codec_dai_node;
429 int ret, i;
430
431 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
432 if (!priv)
433 return -ENOMEM;
434
435 snd_soc_card_set_drvdata(card, priv);
436 card->dev = dev;
437
438 priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias",
439 GPIOF_OUT_INIT_LOW);
440 if (IS_ERR(priv->gpio_mic_bias)) {
441 dev_err(dev, "Failed to get mic bias gpio\n");
442 return PTR_ERR(priv->gpio_mic_bias);
443 }
444
445 ret = snd_soc_of_parse_card_name(card, "model");
446 if (ret < 0) {
447 dev_err(dev, "Card name is not specified\n");
448 return ret;
449 }
450
451 ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
452 if (ret < 0) {
453 dev_err(dev, "Audio routing is not specified or invalid\n");
454 return ret;
455 }
456
457 card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node,
458 "audio-amplifier", 0);
459 if (!card->aux_dev[0].codec_of_node) {
460 dev_err(dev, "audio-amplifier property invalid or missing\n");
461 return -EINVAL;
462 }
463
464 cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0);
465 if (!cpu_dai_node) {
466 dev_err(dev, "i2s-controllers property invalid or missing\n");
467 ret = -EINVAL;
468 goto amp_node_put;
469 }
470
471 codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0);
472 if (!codec_dai_node) {
473 dev_err(dev, "audio-codec property invalid or missing\n");
474 ret = -EINVAL;
475 goto cpu_dai_node_put;
476 }
477
478 for (i = 0; i < card->num_links; i++) {
479 card->dai_link[i].cpu_dai_name = NULL;
480 card->dai_link[i].cpu_name = NULL;
481 card->dai_link[i].platform_name = NULL;
482 card->dai_link[i].codec_of_node = codec_dai_node;
483 card->dai_link[i].cpu_of_node = cpu_dai_node;
484 card->dai_link[i].platform_of_node = cpu_dai_node;
485 }
486
487 ret = devm_snd_soc_register_component(dev, &tm2_component,
488 tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
489 if (ret < 0) {
490 dev_err(dev, "Failed to register component: %d\n", ret);
491 goto codec_dai_node_put;
492 }
493
494 ret = devm_snd_soc_register_card(dev, card);
495 if (ret < 0) {
496 dev_err(dev, "Failed to register card: %d\n", ret);
497 goto codec_dai_node_put;
498 }
499
500codec_dai_node_put:
501 of_node_put(codec_dai_node);
502cpu_dai_node_put:
503 of_node_put(cpu_dai_node);
504amp_node_put:
505 of_node_put(card->aux_dev[0].codec_of_node);
506 return ret;
507}
508
509static int tm2_pm_prepare(struct device *dev)
510{
511 struct snd_soc_card *card = dev_get_drvdata(dev);
512
513 return tm2_stop_sysclk(card);
514}
515
516static void tm2_pm_complete(struct device *dev)
517{
518 struct snd_soc_card *card = dev_get_drvdata(dev);
519
520 tm2_start_sysclk(card);
521}
522
523const struct dev_pm_ops tm2_pm_ops = {
524 .prepare = tm2_pm_prepare,
525 .suspend = snd_soc_suspend,
526 .resume = snd_soc_resume,
527 .complete = tm2_pm_complete,
528 .freeze = snd_soc_suspend,
529 .thaw = snd_soc_resume,
530 .poweroff = snd_soc_poweroff,
531 .restore = snd_soc_resume,
532};
533
534static const struct of_device_id tm2_of_match[] = {
535 { .compatible = "samsung,tm2-audio" },
536 { },
537};
538MODULE_DEVICE_TABLE(of, tm2_of_match);
539
540static struct platform_driver tm2_driver = {
541 .driver = {
542 .name = "tm2-audio",
543 .pm = &tm2_pm_ops,
544 .of_match_table = tm2_of_match,
545 },
546 .probe = tm2_probe,
547};
548module_platform_driver(tm2_driver);
549
550MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>");
551MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
552MODULE_LICENSE("GPL v2");