Commit f617134f authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rt5665', 'asoc/topic/rt5670',...

Merge remote-tracking branches 'asoc/topic/rt5665', 'asoc/topic/rt5670', 'asoc/topic/rt5677', 'asoc/topic/samsung' and 'asoc/topic/simple' into asoc-next
Samsung Exynos5433 TM2(E) audio complex with WM5110 codec
Required properties:
- compatible : "samsung,tm2-audio"
- model : the user-visible name of this sound complex
- audio-codec : the phandle of the wm5110 audio codec node,
as described in ../mfd/arizona.txt
- i2s-controller : the phandle of the I2S controller
- audio-amplifier : the phandle of the MAX98504 amplifier
- samsung,audio-routing : a list of the connections between audio components;
each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source; valid names for sources and sinks are the
WM5110's and MAX98504's pins and the jacks on the
board: HP, SPK, Main Mic, Sub Mic, Third Mic,
Headset Mic
- mic-bias-gpios : GPIO pin that enables the Main Mic bias regulator
Example:
sound {
compatible = "samsung,tm2-audio";
audio-codec = <&wm5110>;
i2s-controller = <&i2s0>;
audio-amplifier = <&max98504>;
mic-bias-gpios = <&gpr3 2 0>;
model = "wm5110";
samsung,audio-routing =
"HP", "HPOUT1L",
"HP", "HPOUT1R",
"SPK", "SPKOUT",
"SPKOUT", "HPOUT2L",
"SPKOUT", "HPOUT2R",
"Main Mic", "MICBIAS2",
"IN1R", "Main Mic";
};
/* /*
* simple_card_core.h * simple_card_utils.h
* *
* Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
* *
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef __SIMPLE_CARD_CORE_H #ifndef __SIMPLE_CARD_UTILS_H
#define __SIMPLE_CARD_CORE_H #define __SIMPLE_CARD_UTILS_H
#include <sound/soc.h> #include <sound/soc.h>
...@@ -68,4 +68,4 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, ...@@ -68,4 +68,4 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
int asoc_simple_card_clean_reference(struct snd_soc_card *card); int asoc_simple_card_clean_reference(struct snd_soc_card *card);
#endif /* __SIMPLE_CARD_CORE_H */ #endif /* __SIMPLE_CARD_UTILS_H */
...@@ -4587,7 +4587,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) ...@@ -4587,7 +4587,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("HP Calibration Failure\n"); pr_err("HP Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0); regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false); regcache_cache_bypass(rt5665->regmap, false);
return; goto out_unlock;
} }
count++; count++;
...@@ -4606,7 +4606,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) ...@@ -4606,7 +4606,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("MONO Calibration Failure\n"); pr_err("MONO Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0); regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false); regcache_cache_bypass(rt5665->regmap, false);
return; goto out_unlock;
} }
count++; count++;
...@@ -4621,6 +4621,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) ...@@ -4621,6 +4621,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
out_unlock:
mutex_unlock(&rt5665->calibrate_mutex); mutex_unlock(&rt5665->calibrate_mutex);
} }
...@@ -4676,11 +4677,9 @@ static int rt5665_i2c_probe(struct i2c_client *i2c, ...@@ -4676,11 +4677,9 @@ static int rt5665_i2c_probe(struct i2c_client *i2c,
} }
if (gpio_is_valid(rt5665->pdata.ldo1_en)) { if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
if (devm_gpio_request(&i2c->dev, rt5665->pdata.ldo1_en, if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
"rt5665")) GPIOF_OUT_INIT_HIGH, "rt5665"))
dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
else if (gpio_direction_output(rt5665->pdata.ldo1_en, 1))
dev_err(&i2c->dev, "Fail gpio_direction gpio_ldo\n");
} }
/* Sleep for 300 ms miniumum */ /* Sleep for 300 ms miniumum */
......
...@@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, ...@@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
RT5670_OSW_L_DIS | RT5670_OSW_R_DIS); RT5670_OSW_L_DIS | RT5670_OSW_R_DIS);
snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1); snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1);
snd_soc_update_bits(codec, RT5670_PWR_ANLG1, snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_LDO_SEL_MASK, 0x3); RT5670_LDO_SEL_MASK, 0x5);
} }
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
...@@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, ...@@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
snd_soc_update_bits(codec, RT5670_PWR_ANLG1, snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_LDO_SEL_MASK, 0x1); RT5670_LDO_SEL_MASK, 0x3);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
if (rt5670->pdata.jd_mode) if (rt5670->pdata.jd_mode)
...@@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); ...@@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id rt5670_acpi_match[] = { static const struct acpi_device_id rt5670_acpi_match[] = {
{ "10EC5670", 0}, { "10EC5670", 0},
{ "10EC5672", 0},
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
...@@ -2826,6 +2827,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { ...@@ -2826,6 +2827,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
}, },
}, },
{
.ident = "Dell Wyse 3040",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
},
},
{} {}
}; };
...@@ -2889,6 +2897,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, ...@@ -2889,6 +2897,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
if (ret != 0) if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC,
RT5670_MCLK_DET, RT5670_MCLK_DET);
if (rt5670->pdata.in2_diff) if (rt5670->pdata.in2_diff)
regmap_update_bits(rt5670->regmap, RT5670_IN2, regmap_update_bits(rt5670->regmap, RT5670_IN2,
RT5670_IN_DF2, RT5670_IN_DF2); RT5670_IN_DF2, RT5670_IN_DF2);
...@@ -2903,7 +2914,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, ...@@ -2903,7 +2914,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2,
RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT);
regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8);
} }
if (rt5670->pdata.jd_mode) { if (rt5670->pdata.jd_mode) {
......
...@@ -1914,6 +1914,7 @@ enum { ...@@ -1914,6 +1914,7 @@ enum {
#define RT5670_IF1_ADC1_IN2_SFT 11 #define RT5670_IF1_ADC1_IN2_SFT 11
#define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10) #define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10)
#define RT5670_IF1_ADC2_IN1_SFT 10 #define RT5670_IF1_ADC2_IN1_SFT 10
#define RT5670_MCLK_DET (0x1 << 3)
/* General Control2 (0xfb) */ /* General Control2 (0xfb) */
#define RT5670_RXDC_SRC_MASK (0x1 << 7) #define RT5670_RXDC_SRC_MASK (0x1 << 7)
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
......
/* /*
* simple-card-core.c * simple-card-utils.c
* *
* Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
* *
...@@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); ...@@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
{ {
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name)
return -EINVAL;
/* Assumes platform == cpu */ /* Assumes platform == cpu */
if (!dai_link->platform_of_node) if (!dai_link->platform_of_node)
dai_link->platform_of_node = dai_link->cpu_of_node; dai_link->platform_of_node = dai_link->cpu_of_node;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <sound/soc-dai.h> #include <sound/soc-dai.h>
#include <sound/simple_card_utils.h> #include <sound/simple_card_utils.h>
struct asoc_simple_card_priv { struct simple_card_data {
struct snd_soc_card snd_card; struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf; struct snd_soc_codec_conf codec_conf;
struct asoc_simple_dai *dai_props; struct asoc_simple_dai *dai_props;
...@@ -42,7 +42,7 @@ struct asoc_simple_card_priv { ...@@ -42,7 +42,7 @@ struct asoc_simple_card_priv {
static int asoc_simple_card_startup(struct snd_pcm_substream *substream) static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct asoc_simple_dai *dai_props = struct asoc_simple_dai *dai_props =
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
...@@ -52,7 +52,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) ...@@ -52,7 +52,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct asoc_simple_dai *dai_props = struct asoc_simple_dai *dai_props =
simple_priv_to_props(priv, rtd->num); simple_priv_to_props(priv, rtd->num);
...@@ -66,7 +66,7 @@ static const struct snd_soc_ops asoc_simple_card_ops = { ...@@ -66,7 +66,7 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai; struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dai_props; struct asoc_simple_dai *dai_props;
...@@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) ...@@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_interval *rate = hw_param_interval(params, struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE); SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params, 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,8 +101,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0; return 0;
} }
static int asoc_simple_card_parse_links(struct device_node *np, static int asoc_simple_card_dai_link_of(struct device_node *np,
struct asoc_simple_card_priv *priv, struct simple_card_data *priv,
unsigned int daifmt, unsigned int daifmt,
int idx, bool is_fe) int idx, bool is_fe)
{ {
...@@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np, ...@@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np,
return 0; return 0;
} }
static int asoc_simple_card_dai_link_of(struct device_node *node, static int asoc_simple_card_parse_of(struct device_node *node,
struct asoc_simple_card_priv *priv) struct simple_card_data *priv)
{ {
struct device *dev = simple_priv_to_dev(priv); struct device *dev = simple_priv_to_dev(priv);
struct device_node *np; struct device_node *np;
unsigned int daifmt = 0; unsigned int daifmt = 0;
int ret, i;
bool is_fe; bool is_fe;
int ret, i;
if (!node)
return -EINVAL;
ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing");
if (ret < 0)
return ret;
/* sampling rate convert */
of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
/* channels transfer */
of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
/* find 1st codec */ /* find 1st codec */
np = of_get_child_by_name(node, PREFIX "codec"); np = of_get_child_by_name(node, PREFIX "codec");
if (!np) if (!np)
return -ENODEV; return -ENODEV;
ret = asoc_simple_card_parse_daifmt(dev, node, np, ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
PREFIX, &daifmt);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ...@@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
if (strcmp(np->name, PREFIX "cpu") == 0) if (strcmp(np->name, PREFIX "cpu") == 0)
is_fe = true; is_fe = true;
ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
if (ret < 0) if (ret < 0)
return ret; return ret;
i++; i++;
} }
return 0;
}
static int asoc_simple_card_parse_of(struct device_node *node,
struct asoc_simple_card_priv *priv,
struct device *dev)
{
struct asoc_simple_dai *props;
struct snd_soc_dai_link *links;
int ret;
int num;
if (!node)
return -EINVAL;
num = of_get_child_count(node);
props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
if (!props || !links)
return -ENOMEM;
priv->dai_props = props;
priv->dai_link = links;
/* Init snd_soc_card */
priv->snd_card.owner = THIS_MODULE;
priv->snd_card.dev = dev;
priv->snd_card.dai_link = priv->dai_link;
priv->snd_card.num_links = num;
priv->snd_card.codec_conf = &priv->codec_conf;
priv->snd_card.num_configs = 1;
ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing");
if (ret < 0)
return ret;
/* sampling rate convert */
of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
/* channels transfer */
of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
ret = asoc_simple_card_dai_link_of(node, priv);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -286,17 +253,37 @@ static int asoc_simple_card_parse_of(struct device_node *node, ...@@ -286,17 +253,37 @@ static int asoc_simple_card_parse_of(struct device_node *node,
static int asoc_simple_card_probe(struct platform_device *pdev) static int asoc_simple_card_probe(struct platform_device *pdev)
{ {
struct asoc_simple_card_priv *priv; struct simple_card_data *priv;
struct device_node *np = pdev->dev.of_node; struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dai_props;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int ret; struct device_node *np = pdev->dev.of_node;
int num, ret;
/* Allocate the private data */ /* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
ret = asoc_simple_card_parse_of(np, priv, dev); num = of_get_child_count(np);
dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
if (!dai_props || !dai_link)
return -ENOMEM;
priv->dai_props = dai_props;
priv->dai_link = dai_link;
/* Init snd_soc_card */
priv->snd_card.owner = THIS_MODULE;
priv->snd_card.dev = dev;
priv->snd_card.dai_link = priv->dai_link;
priv->snd_card.num_links = num;
priv->snd_card.codec_conf = &priv->codec_conf;
priv->snd_card.num_configs = 1;
ret = asoc_simple_card_parse_of(np, priv);
if (ret < 0) { if (ret < 0) {
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret); dev_err(dev, "parse error %d\n", ret);
......
menuconfig SND_SOC_SAMSUNG menuconfig SND_SOC_SAMSUNG
tristate "ASoC support for Samsung" tristate "ASoC support for Samsung"
depends on (PLAT_SAMSUNG || ARCH_EXYNOS) depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM
---help--- ---help---
Say Y or M if you want to add support for codecs attached to Say Y or M if you want to add support for codecs attached to
...@@ -22,10 +23,6 @@ config SND_S3C2412_SOC_I2S ...@@ -22,10 +23,6 @@ config SND_S3C2412_SOC_I2S
config SND_SAMSUNG_PCM config SND_SAMSUNG_PCM
tristate "Samsung PCM interface support" tristate "Samsung PCM interface support"
config SND_SAMSUNG_AC97
tristate
select SND_SOC_AC97_BUS
config SND_SAMSUNG_SPDIF config SND_SAMSUNG_SPDIF
tristate "Samsung SPDIF transmitter support" tristate "Samsung SPDIF transmitter support"
select SND_SOC_SPDIF select SND_SOC_SPDIF
...@@ -53,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 ...@@ -53,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK" tristate "SoC I2S Audio support for WM8580 on SMDK"
depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 depends on MACH_SMDK6410 || COMPILE_TEST
depends on I2C depends on I2C
select SND_SOC_WM8580 select SND_SOC_WM8580
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
...@@ -69,26 +66,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994 ...@@ -69,26 +66,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
help help
Say Y if you want to add support for SoC audio on the SMDKs. Say Y if you want to add support for SoC audio on the SMDKs.
config SND_SOC_SAMSUNG_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
depends on MACH_SMDK2443
select AC97_BUS
select SND_SOC_AC97_CODEC
select SND_SAMSUNG_AC97
help
Say Y if you want to add support for SoC audio on smdk2443
with the WM9710.
config SND_SOC_SAMSUNG_LN2440SBC_ALC650
tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
depends on ARCH_S3C24XX
select AC97_BUS
select SND_SOC_AC97_CODEC
select SND_SAMSUNG_AC97
help
Say Y if you want to add support for SoC audio on ln2440sbc
with the ALC650.
config SND_SOC_SAMSUNG_S3C24XX_UDA134X config SND_SOC_SAMSUNG_S3C24XX_UDA134X
tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
depends on ARCH_S3C24XX depends on ARCH_S3C24XX
...@@ -131,17 +108,10 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 ...@@ -131,17 +108,10 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
help help
This driver provides audio support for HP iPAQ RX1950 PDA. This driver provides audio support for HP iPAQ RX1950 PDA.
config SND_SOC_SAMSUNG_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
select SND_SOC_WM9713
select SND_SAMSUNG_AC97
help
Say Y if you want to add support for SoC audio on the SMDK.
config SND_SOC_SMARTQ config SND_SOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board" tristate "SoC I2S Audio support for SmartQ board"
depends on MACH_SMARTQ && I2C depends on MACH_SMARTQ || COMPILE_TEST
depends on I2C
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
select SND_SOC_WM8750 select SND_SOC_WM8750
...@@ -151,15 +121,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF ...@@ -151,15 +121,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
help help
Say Y if you want to add support for SoC S/PDIF audio on the SMDK. Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
config SND_SOC_SMDK_WM8580_PCM
tristate "SoC PCM Audio support for WM8580 on SMDK"
depends on MACH_SMDKV210 || MACH_SMDKC110
depends on I2C
select SND_SOC_WM8580
select SND_SAMSUNG_PCM
help
Say Y if you want to add support for SoC audio on the SMDK.
config SND_SOC_SMDK_WM8994_PCM config SND_SOC_SMDK_WM8994_PCM
tristate "SoC PCM Audio support for WM8994 on SMDK" tristate "SoC PCM Audio support for WM8994 on SMDK"
depends on I2C=y depends on I2C=y
...@@ -229,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631 ...@@ -229,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
select SND_SOC_RT5631 select SND_SOC_RT5631
config SND_SOC_SAMSUNG_TM2_WM5110
tristate "SoC I2S Audio support for WM5110 on TM2 board"
depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
select SND_SOC_MAX98504
select SND_SOC_WM5110
select SND_SAMSUNG_I2S
help
Say Y if you want to add support for SoC audio on the TM2 board.
endif #SND_SOC_SAMSUNG endif #SND_SOC_SAMSUNG
...@@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o ...@@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o
snd-soc-idma-objs := idma.o snd-soc-idma-objs := idma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
snd-soc-ac97-objs := ac97.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-samsung-spdif-objs := spdif.o snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o snd-soc-pcm-objs := pcm.o
...@@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o ...@@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o
obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
...@@ -36,7 +34,6 @@ snd-soc-snow-objs := snow.o ...@@ -36,7 +34,6 @@ snd-soc-snow-objs := snow.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
snd-soc-smdk-spdif-objs := smdk_spdif.o snd-soc-smdk-spdif-objs := smdk_spdif.o
snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
snd-soc-speyside-objs := speyside.o snd-soc-speyside-objs := speyside.o
snd-soc-tobermory-objs := tobermory.o snd-soc-tobermory-objs := tobermory.o
...@@ -44,11 +41,10 @@ snd-soc-lowland-objs := lowland.o ...@@ -44,11 +41,10 @@ snd-soc-lowland-objs := lowland.o
snd-soc-littlemill-objs := littlemill.o snd-soc-littlemill-objs := littlemill.o
snd-soc-bells-objs := bells.o snd-soc-bells-objs := bells.o
snd-soc-arndale-rt5631-objs := arndale_rt5631.o snd-soc-arndale-rt5631-objs := arndale_rt5631.o
snd-soc-tm2-wm5110-objs := tm2_wm5110.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(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 ...@@ -58,10 +54,8 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
...@@ -69,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o ...@@ -69,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o
/* sound/soc/samsung/ac97.c
*
* ALSA SoC Audio Layer - S3C AC97 Controller driver
* Evolved from s3c2443-ac97.c
*
* Copyright (c) 2010 Samsung Electronics Co. Ltd
* Author: Jaswinder Singh <jassisinghbrar@gmail.com>
* Credits: Graeme Gregory, Sean Choi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <sound/soc.h>
#include "regs-ac97.h"
#include <linux/platform_data/asoc-s3c.h>
#include "dma.h"
#define AC_CMD_ADDR(x) (x << 16)
#define AC_CMD_DATA(x) (x & 0xffff)
#define S3C_AC97_DAI_PCM 0
#define S3C_AC97_DAI_MIC 1
struct s3c_ac97_info {
struct clk *ac97_clk;
void __iomem *regs;
struct mutex lock;
struct completion done;
};
static struct s3c_ac97_info s3c_ac97;
static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = {
.addr_width = 4,
};
static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = {
.addr_width = 4,
};
static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = {
.addr_width = 4,
};
static void s3c_ac97_activate(struct snd_ac97 *ac97)
{
u32 ac_glbctrl, stat;
stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
reinit_completion(&s3c_ac97.done);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
pr_err("AC97: Unable to activate!\n");
}
static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
u32 ac_glbctrl, ac_codec_cmd;
u32 stat, addr, data;
mutex_lock(&s3c_ac97.lock);
s3c_ac97_activate(ac97);
reinit_completion(&s3c_ac97.done);
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
udelay(50);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
pr_err("AC97: Unable to read!\n");
stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
addr = (stat >> 16) & 0x7f;
data = (stat & 0xffff);
if (addr != reg)
pr_err("ac97: req addr = %02x, rep addr = %02x\n",
reg, addr);
mutex_unlock(&s3c_ac97.lock);
return (unsigned short)data;
}
static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
u32 ac_glbctrl, ac_codec_cmd;
mutex_lock(&s3c_ac97.lock);
s3c_ac97_activate(ac97);
reinit_completion(&s3c_ac97.done);
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
udelay(50);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
pr_err("AC97: Unable to write!\n");
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
mutex_unlock(&s3c_ac97.lock);
}
static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
{
pr_debug("AC97: Cold reset\n");
writel(S3C_AC97_GLBCTRL_COLDRESET,
s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
}
static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
{
u32 stat;
stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
pr_debug("AC97: Warm reset\n");
writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
msleep(1);
s3c_ac97_activate(ac97);
}
static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
{
u32 ac_glbctrl, ac_glbstat;
ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
complete(&s3c_ac97.done);
}
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl |= (1<<30); /* Clear interrupt */
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
return IRQ_HANDLED;
}
static struct snd_ac97_bus_ops s3c_ac97_ops = {
.read = s3c_ac97_read,
.write = s3c_ac97_write,
.warm_reset = s3c_ac97_warm_reset,
.reset = s3c_ac97_cold_reset,
};
static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
u32 ac_glbctrl;
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
else
ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
else
ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
}
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
return 0;
}
static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
u32 ac_glbctrl;
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
}
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
return 0;
}
static const struct snd_soc_dai_ops s3c_ac97_dai_ops = {
.trigger = s3c_ac97_trigger,
};
static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
.trigger = s3c_ac97_mic_trigger,
};
static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
{
snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
return 0;
}
static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
{
snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
return 0;
}
static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "samsung-ac97",
.bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.capture = {
.stream_name = "AC97 Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.probe = s3c_ac97_dai_probe,
.ops = &s3c_ac97_dai_ops,
},
[S3C_AC97_DAI_MIC] = {
.name = "samsung-ac97-mic",
.bus_control = true,
.capture = {
.stream_name = "AC97 Mic Capture",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
.probe = s3c_ac97_mic_dai_probe,
.ops = &s3c_ac97_mic_dai_ops,
},
};
static const struct snd_soc_component_driver s3c_ac97_component = {
.name = "s3c-ac97",
};
static int s3c_ac97_probe(struct platform_device *pdev)
{
struct resource *mem_res, *irq_res;
struct s3c_audio_pdata *ac97_pdata;
int ret;
ac97_pdata = pdev->dev.platform_data;
if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
return -EINVAL;
}
/* Check for availability of necessary resource */
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
return -ENXIO;
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(s3c_ac97.regs))
return PTR_ERR(s3c_ac97.regs);
s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback;
s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA;
s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture;
s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA;
s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic;
s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA;
init_completion(&s3c_ac97.done);
mutex_init(&s3c_ac97.lock);
s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97");
if (IS_ERR(s3c_ac97.ac97_clk)) {
dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
ret = -ENODEV;
goto err2;
}
clk_prepare_enable(s3c_ac97.ac97_clk);
if (ac97_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL;
goto err3;
}
ret = request_irq(irq_res->start, s3c_ac97_irq,
0, "AC97", NULL);
if (ret < 0) {
dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
goto err4;
}
ret = snd_soc_set_ac97_ops(&s3c_ac97_ops);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
goto err4;
}
ret = samsung_asoc_dma_platform_register(&pdev->dev,
ac97_pdata->dma_filter,
NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5;
}
ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
return 0;
err5:
free_irq(irq_res->start, NULL);
err4:
err3:
clk_disable_unprepare(s3c_ac97.ac97_clk);
err2:
snd_soc_set_ac97_ops(NULL);
return ret;
}
static int s3c_ac97_remove(struct platform_device *pdev)
{
struct resource *irq_res;
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res)
free_irq(irq_res->start, NULL);
clk_disable_unprepare(s3c_ac97.ac97_clk);
snd_soc_set_ac97_ops(NULL);
return 0;
}
static struct platform_driver s3c_ac97_driver = {
.probe = s3c_ac97_probe,
.remove = s3c_ac97_remove,
.driver = {
.name = "samsung-ac97",
},
};
module_platform_driver(s3c_ac97_driver);
MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:samsung-ac97");
...@@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) ...@@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
{ {
struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
unsigned long flags;
if (!is_secondary(i2s)) { if (!is_secondary(i2s)) {
if (i2s->quirks & QUIRK_NEED_RSTCLR) { if (i2s->quirks & QUIRK_NEED_RSTCLR) {
spin_lock(i2s->lock); spin_lock_irqsave(i2s->lock, flags);
writel(0, i2s->addr + I2SCON); writel(0, i2s->addr + I2SCON);
spin_unlock(i2s->lock); spin_unlock_irqrestore(i2s->lock, flags);
} }
} }
......
/*
* SoC audio for ln2440sbc
*
* Copyright 2007 KonekTel, a.s.
* Author: Ivan Kuten
* ivan.kuten@promwad.com
*
* Heavily based on smdk2443_wm9710.c
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <sound/soc.h>
static struct snd_soc_card ln2440sbc;
static struct snd_soc_dai_link ln2440sbc_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
.cpu_dai_name = "samsung-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
.platform_name = "samsung-ac97",
},
};
static struct snd_soc_card ln2440sbc = {
.name = "LN2440SBC",
.owner = THIS_MODULE,
.dai_link = ln2440sbc_dai,
.num_links = ARRAY_SIZE(ln2440sbc_dai),
};
static struct platform_device *ln2440sbc_snd_ac97_device;
static int __init ln2440sbc_init(void)
{
int ret;
ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
if (!ln2440sbc_snd_ac97_device)
return -ENOMEM;
platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
ret = platform_device_add(ln2440sbc_snd_ac97_device);
if (ret)
platform_device_put(ln2440sbc_snd_ac97_device);
return ret;
}
static void __exit ln2440sbc_exit(void)
{
platform_device_unregister(ln2440sbc_snd_ac97_device);
}
module_init(ln2440sbc_init);
module_exit(ln2440sbc_exit);
/* Module information */
MODULE_AUTHOR("Ivan Kuten");
MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
MODULE_LICENSE("GPL");
...@@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) ...@@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
pcm_pdata = pdev->dev.platform_data; pcm_pdata = pdev->dev.platform_data;
/* Check for availability of necessary resource */
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
dev_err(&pdev->dev, "Unable to get register resource\n");
return -ENXIO;
}
if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n"); dev_err(&pdev->dev, "Unable to configure gpio\n");
return -EINVAL; return -EINVAL;
...@@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) ...@@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
/* Default is 128fs */ /* Default is 128fs */
pcm->sclk_per_fs = 128; pcm->sclk_per_fs = 128;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(pcm->regs))
return PTR_ERR(pcm->regs);
pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus"); pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");
if (IS_ERR(pcm->cclk)) { if (IS_ERR(pcm->cclk)) {
dev_err(&pdev->dev, "failed to get audio-bus\n"); dev_err(&pdev->dev, "failed to get audio-bus clock\n");
ret = PTR_ERR(pcm->cclk); return PTR_ERR(pcm->cclk);
goto err1;
} }
clk_prepare_enable(pcm->cclk); clk_prepare_enable(pcm->cclk);
/* record our pcm structure for later use in the callbacks */ /* record our pcm structure for later use in the callbacks */
dev_set_drvdata(&pdev->dev, pcm); dev_set_drvdata(&pdev->dev, pcm);
if (!request_mem_region(mem_res->start,
resource_size(mem_res), "samsung-pcm")) {
dev_err(&pdev->dev, "Unable to request register region\n");
ret = -EBUSY;
goto err2;
}
pcm->regs = ioremap(mem_res->start, 0x100);
if (pcm->regs == NULL) {
dev_err(&pdev->dev, "cannot ioremap registers\n");
ret = -ENXIO;
goto err3;
}
pcm->pclk = devm_clk_get(&pdev->dev, "pcm"); pcm->pclk = devm_clk_get(&pdev->dev, "pcm");
if (IS_ERR(pcm->pclk)) { if (IS_ERR(pcm->pclk)) {
dev_err(&pdev->dev, "failed to get pcm_clock\n"); dev_err(&pdev->dev, "failed to get pcm clock\n");
ret = -ENOENT; ret = PTR_ERR(pcm->pclk);
goto err4; goto err_dis_cclk;
} }
clk_prepare_enable(pcm->pclk); clk_prepare_enable(pcm->pclk);
...@@ -569,7 +552,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) ...@@ -569,7 +552,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
NULL, NULL); NULL, NULL);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
goto err5; goto err_dis_pclk;
} }
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
...@@ -578,36 +561,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) ...@@ -578,36 +561,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
&s3c_pcm_dai[pdev->id], 1); &s3c_pcm_dai[pdev->id], 1);
if (ret != 0) { if (ret != 0) {
dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
goto err6; goto err_dis_pm;
} }
return 0; return 0;
err6:
err_dis_pm:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err5: err_dis_pclk:
clk_disable_unprepare(pcm->pclk); clk_disable_unprepare(pcm->pclk);
err4: err_dis_cclk:
iounmap(pcm->regs);
err3:
release_mem_region(mem_res->start, resource_size(mem_res));
err2:
clk_disable_unprepare(pcm->cclk); clk_disable_unprepare(pcm->cclk);
err1:
return ret; return ret;
} }
static int s3c_pcm_dev_remove(struct platform_device *pdev) static int s3c_pcm_dev_remove(struct platform_device *pdev)
{ {
struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
struct resource *mem_res;
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
iounmap(pcm->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem_res->start, resource_size(mem_res));
clk_disable_unprepare(pcm->cclk); clk_disable_unprepare(pcm->cclk);
clk_disable_unprepare(pcm->pclk); clk_disable_unprepare(pcm->pclk);
......
/*
* Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* S3C2440 AC97 Controller
*/
#ifndef __SAMSUNG_REGS_AC97_H__
#define __SAMSUNG_REGS_AC97_H__
#define S3C_AC97_GLBCTRL (0x00)
#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22)
#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21)
#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20)
#define S3C_AC97_GLBCTRL_MICINORIE (1<<19)
#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18)
#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17)
#define S3C_AC97_GLBCTRL_MICINTIE (1<<16)
#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12)
#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12)
#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12)
#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12)
#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10)
#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10)
#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10)
#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10)
#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8)
#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8)
#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8)
#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8)
#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3)
#define S3C_AC97_GLBCTRL_ACLINKON (1<<2)
#define S3C_AC97_GLBCTRL_WARMRESET (1<<1)
#define S3C_AC97_GLBCTRL_COLDRESET (1<<0)
#define S3C_AC97_GLBSTAT (0x04)
#define S3C_AC97_GLBSTAT_CODECREADY (1<<22)
#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21)
#define S3C_AC97_GLBSTAT_PCMINORI (1<<20)
#define S3C_AC97_GLBSTAT_MICINORI (1<<19)
#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18)
#define S3C_AC97_GLBSTAT_PCMINTI (1<<17)
#define S3C_AC97_GLBSTAT_MICINTI (1<<16)
#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0)
#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0)
#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0)
#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0)
#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0)
#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0)
#define S3C_AC97_CODEC_CMD (0x08)
#define S3C_AC97_CODEC_CMD_READ (1<<23)
#define S3C_AC97_STAT (0x0c)
#define S3C_AC97_PCM_ADDR (0x10)
#define S3C_AC97_PCM_DATA (0x18)
#define S3C_AC97_MIC_DATA (0x1C)
#endif /* __SAMSUNG_REGS_AC97_H__ */
...@@ -30,8 +30,6 @@ ...@@ -30,8 +30,6 @@
#include "dma.h" #include "dma.h"
#include "s3c24xx-i2s.h" #include "s3c24xx-i2s.h"
#include <linux/platform_data/asoc-s3c.h>
static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
.addr_width = 2, .addr_width = 2,
}; };
...@@ -56,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on) ...@@ -56,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on)
u32 iiscon; u32 iiscon;
u32 iismod; u32 iismod;
pr_debug("Entered %s\n", __func__);
iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
...@@ -101,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on) ...@@ -101,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on)
u32 iiscon; u32 iiscon;
u32 iismod; u32 iismod;
pr_debug("Entered %s\n", __func__);
iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
...@@ -149,8 +143,6 @@ static int s3c24xx_snd_lrsync(void) ...@@ -149,8 +143,6 @@ static int s3c24xx_snd_lrsync(void)
u32 iiscon; u32 iiscon;
int timeout = 50; /* 5ms */ int timeout = 50; /* 5ms */
pr_debug("Entered %s\n", __func__);
while (1) { while (1) {
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
if (iiscon & S3C2410_IISCON_LRINDEX) if (iiscon & S3C2410_IISCON_LRINDEX)
...@@ -169,8 +161,6 @@ static int s3c24xx_snd_lrsync(void) ...@@ -169,8 +161,6 @@ static int s3c24xx_snd_lrsync(void)
*/ */
static inline int s3c24xx_snd_is_clkmaster(void) static inline int s3c24xx_snd_is_clkmaster(void)
{ {
pr_debug("Entered %s\n", __func__);
return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
} }
...@@ -182,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -182,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
{ {
u32 iismod; u32 iismod;
pr_debug("Entered %s\n", __func__);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod); pr_debug("hw_params r: IISMOD: %x \n", iismod);
...@@ -211,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -211,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params w: IISMOD: %x \n", iismod); pr_debug("hw_params w: IISMOD: %x \n", iismod);
return 0; return 0;
} }
...@@ -221,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -221,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_dmaengine_dai_dma_data *dma_data; struct snd_dmaengine_dai_dma_data *dma_data;
u32 iismod; u32 iismod;
pr_debug("Entered %s\n", __func__);
dma_data = snd_soc_dai_get_dma_data(dai, substream); dma_data = snd_soc_dai_get_dma_data(dai, substream);
/* Working copies of register */ /* Working copies of register */
...@@ -244,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -244,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params w: IISMOD: %x\n", iismod); pr_debug("hw_params w: IISMOD: %x\n", iismod);
return 0; return 0;
} }
...@@ -252,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -252,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
{ {
int ret = 0; int ret = 0;
pr_debug("Entered %s\n", __func__);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
...@@ -295,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, ...@@ -295,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
{ {
u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("Entered %s\n", __func__);
iismod &= ~S3C2440_IISMOD_MPLL; iismod &= ~S3C2440_IISMOD_MPLL;
switch (clk_id) { switch (clk_id) {
...@@ -321,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, ...@@ -321,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
{ {
u32 reg; u32 reg;
pr_debug("Entered %s\n", __func__);
switch (div_id) { switch (div_id) {
case S3C24XX_DIV_BCLK: case S3C24XX_DIV_BCLK:
reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
...@@ -356,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); ...@@ -356,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
{ {
pr_debug("Entered %s\n", __func__);
snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,
&s3c24xx_i2s_pcm_stereo_in); &s3c24xx_i2s_pcm_stereo_in);
...@@ -383,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) ...@@ -383,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
{ {
pr_debug("Entered %s\n", __func__);
s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 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,7 +375,6 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
{ {
pr_debug("Entered %s\n", __func__);
clk_prepare_enable(s3c24xx_i2s.iis_clk); clk_prepare_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); 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,7 +389,6 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
#define s3c24xx_i2s_resume NULL #define s3c24xx_i2s_resume NULL
#endif #endif
#define S3C24XX_I2S_RATES \ #define S3C24XX_I2S_RATES \
(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 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,41 +425,28 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = {
static int s3c24xx_iis_dev_probe(struct platform_device *pdev) static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{ {
int ret = 0;
struct resource *res; struct resource *res;
struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); int ret;
if (!pdata) {
dev_err(&pdev->dev, "missing platform data");
return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Can't get IO resource.\n");
return -ENOENT;
}
s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(s3c24xx_i2s.regs)) if (IS_ERR(s3c24xx_i2s.regs))
return PTR_ERR(s3c24xx_i2s.regs); return PTR_ERR(s3c24xx_i2s.regs);
s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO;
s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
ret = samsung_asoc_dma_platform_register(&pdev->dev, ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL,
pdata->dma_filter,
NULL, NULL); NULL, NULL);
if (ret) { if (ret) {
pr_err("failed to register the dma: %d\n", ret); dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret);
return ret; return ret;
} }
ret = devm_snd_soc_register_component(&pdev->dev, ret = devm_snd_soc_register_component(&pdev->dev,
&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
if (ret) if (ret)
pr_err("failed to register the dai\n"); dev_err(&pdev->dev, "Failed to register the DAI\n");
return ret; return ret;
} }
......
...@@ -19,9 +19,15 @@ ...@@ -19,9 +19,15 @@
#include <sound/s3c24xx_uda134x.h> #include <sound/s3c24xx_uda134x.h>
#include "regs-iis.h" #include "regs-iis.h"
#include "s3c24xx-i2s.h" #include "s3c24xx-i2s.h"
struct s3c24xx_uda134x {
struct clk *xtal;
struct clk *pclk;
struct mutex clk_lock;
int clk_users;
};
/* #define ENFORCE_RATES 1 */ /* #define ENFORCE_RATES 1 */
/* /*
Unfortunately the S3C24XX in master mode has a limited capacity of Unfortunately the S3C24XX in master mode has a limited capacity of
...@@ -36,15 +42,6 @@ ...@@ -36,15 +42,6 @@
possible an error will be returned. possible an error will be returned.
*/ */
static struct clk *xtal;
static struct clk *pclk;
/* this is need because we don't have a place where to keep the
* pointers to the clocks in each substream. We get the clocks only
* when we are actually using them so we don't block stuff like
* frequency change or oscillator power-off */
static int clk_users;
static DEFINE_MUTEX(clk_lock);
static unsigned int rates[33 * 2]; static unsigned int rates[33 * 2];
#ifdef ENFORCE_RATES #ifdef ENFORCE_RATES
static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
...@@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { ...@@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
#ifdef ENFORCE_RATES
struct snd_pcm_runtime *runtime = substream->runtime;
#endif
int ret = 0; int ret = 0;
mutex_lock(&clk_lock); mutex_lock(&priv->clk_lock);
if (clk_users == 0) { if (priv->clk_users == 0) {
xtal = clk_get(rtd->dev, "xtal"); priv->xtal = clk_get(rtd->dev, "xtal");
if (IS_ERR(xtal)) { if (IS_ERR(priv->xtal)) {
dev_err(rtd->dev, "%s cannot get xtal\n", __func__); dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
ret = PTR_ERR(xtal); ret = PTR_ERR(priv->xtal);
} else { } else {
pclk = clk_get(cpu_dai->dev, "iis"); priv->pclk = clk_get(cpu_dai->dev, "iis");
if (IS_ERR(pclk)) { if (IS_ERR(priv->pclk)) {
dev_err(rtd->dev, "%s cannot get pclk\n", dev_err(rtd->dev, "%s cannot get pclk\n",
__func__); __func__);
clk_put(xtal); clk_put(priv->xtal);
ret = PTR_ERR(pclk); ret = PTR_ERR(priv->pclk);
} }
} }
if (!ret) { if (!ret) {
...@@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) ...@@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
int fs = i ? 256 : 384; int fs = i ? 256 : 384;
rates[i*33] = clk_get_rate(xtal) / fs; rates[i*33] = clk_get_rate(priv->xtal) / fs;
for (j = 1; j < 33; j++) for (j = 1; j < 33; j++)
rates[i*33 + j] = clk_get_rate(pclk) / rates[i*33 + j] = clk_get_rate(priv->pclk) /
(j * fs); (j * fs);
} }
} }
} }
clk_users += 1; priv->clk_users += 1;
mutex_unlock(&clk_lock); mutex_unlock(&priv->clk_lock);
if (!ret) { if (!ret) {
#ifdef ENFORCE_RATES #ifdef ENFORCE_RATES
ret = snd_pcm_hw_constraint_list(runtime, 0, ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_rates); &hw_constraints_rates);
if (ret < 0) if (ret < 0)
...@@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) ...@@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
{ {
mutex_lock(&clk_lock); struct snd_soc_pcm_runtime *rtd = substream->private_data;
clk_users -= 1; struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
if (clk_users == 0) {
clk_put(xtal); mutex_lock(&priv->clk_lock);
xtal = NULL; priv->clk_users -= 1;
clk_put(pclk); if (priv->clk_users == 0) {
pclk = NULL; clk_put(priv->xtal);
priv->xtal = NULL;
clk_put(priv->pclk);
priv->pclk = NULL;
} }
mutex_unlock(&clk_lock); mutex_unlock(&priv->clk_lock);
} }
static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
...@@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = { ...@@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
static int s3c24xx_uda134x_probe(struct platform_device *pdev) static int s3c24xx_uda134x_probe(struct platform_device *pdev)
{ {
struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
struct s3c24xx_uda134x *priv;
int ret; int ret;
platform_set_drvdata(pdev, card); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
mutex_init(&priv->clk_lock);
card->dev = &pdev->dev; card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) if (ret)
......
/*
* smdk2443_wm9710.c -- SoC audio for smdk2443
*
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <sound/soc.h>
static struct snd_soc_card smdk2443;
static struct snd_soc_dai_link smdk2443_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 HiFi",
.cpu_dai_name = "samsung-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
.platform_name = "samsung-ac97",
},
};
static struct snd_soc_card smdk2443 = {
.name = "SMDK2443",
.owner = THIS_MODULE,
.dai_link = smdk2443_dai,
.num_links = ARRAY_SIZE(smdk2443_dai),
};
static struct platform_device *smdk2443_snd_ac97_device;
static int __init smdk2443_init(void)
{
int ret;
smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
if (!smdk2443_snd_ac97_device)
return -ENOMEM;
platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
ret = platform_device_add(smdk2443_snd_ac97_device);
if (ret)
platform_device_put(smdk2443_snd_ac97_device);
return ret;
}
static void __exit smdk2443_exit(void)
{
platform_device_unregister(smdk2443_snd_ac97_device);
}
module_init(smdk2443_init);
module_exit(smdk2443_exit);
/* Module information */
MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
MODULE_LICENSE("GPL");
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <asm/mach-types.h>
#include "../codecs/wm8580.h" #include "../codecs/wm8580.h"
#include "i2s.h" #include "i2s.h"
...@@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) ...@@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
enum { enum {
PRI_PLAYBACK = 0, PRI_PLAYBACK = 0,
PRI_CAPTURE, PRI_CAPTURE,
SEC_PLAYBACK,
}; };
#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ #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,7 +154,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
[PRI_PLAYBACK] = { /* Primary Playback i/f */ [PRI_PLAYBACK] = { /* Primary Playback i/f */
.name = "WM8580 PAIF RX", .name = "WM8580 PAIF RX",
.stream_name = "Playback", .stream_name = "Playback",
.cpu_dai_name = "samsung-i2s.0", .cpu_dai_name = "samsung-i2s.2",
.codec_dai_name = "wm8580-hifi-playback", .codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-i2s.0", .platform_name = "samsung-i2s.0",
.codec_name = "wm8580.0-001b", .codec_name = "wm8580.0-001b",
...@@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = { ...@@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
[PRI_CAPTURE] = { /* Primary Capture i/f */ [PRI_CAPTURE] = { /* Primary Capture i/f */
.name = "WM8580 PAIF TX", .name = "WM8580 PAIF TX",
.stream_name = "Capture", .stream_name = "Capture",
.cpu_dai_name = "samsung-i2s.0", .cpu_dai_name = "samsung-i2s.2",
.codec_dai_name = "wm8580-hifi-capture", .codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-i2s.0", .platform_name = "samsung-i2s.0",
.codec_name = "wm8580.0-001b", .codec_name = "wm8580.0-001b",
...@@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = { ...@@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = {
.init = smdk_wm8580_init_paiftx, .init = smdk_wm8580_init_paiftx,
.ops = &smdk_ops, .ops = &smdk_ops,
}, },
[SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
.name = "Sec_FIFO TX",
.stream_name = "Playback",
.cpu_dai_name = "samsung-i2s-sec",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-i2s-sec",
.codec_name = "wm8580.0-001b",
.dai_fmt = SMDK_DAI_FMT,
.ops = &smdk_ops,
},
}; };
static struct snd_soc_card smdk = { static struct snd_soc_card smdk = {
.name = "SMDK-I2S", .name = "SMDK-I2S",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = smdk_dai, .dai_link = smdk_dai,
.num_links = 2, .num_links = ARRAY_SIZE(smdk_dai),
.dapm_widgets = smdk_wm8580_dapm_widgets, .dapm_widgets = smdk_wm8580_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets),
...@@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device; ...@@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device;
static int __init smdk_audio_init(void) static int __init smdk_audio_init(void)
{ {
int ret; int ret;
char *str;
if (machine_is_smdkc100()
|| machine_is_smdkv210() || machine_is_smdkc110()) {
smdk.num_links = 3;
} else if (machine_is_smdk6410()) {
str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
str[strlen(str) - 1] = '2';
str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
str[strlen(str) - 1] = '2';
}
smdk_snd_device = platform_device_alloc("soc-audio", -1); smdk_snd_device = platform_device_alloc("soc-audio", -1);
if (!smdk_snd_device) if (!smdk_snd_device)
......
/*
* sound/soc/samsung/smdk_wm8580pcm.c
*
* Copyright (c) 2011 Samsung Electronics Co. Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <asm/mach-types.h>
#include "../codecs/wm8580.h"
#include "pcm.h"
/*
* Board Settings:
* o '1' means 'ON'
* o '0' means 'OFF'
* o 'X' means 'Don't care'
*
* SMDK6410 Base B/D: CFG1-0000, CFG2-1111
* SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000
*/
#define SMDK_WM8580_EXT_OSC 12000000
#define SMDK_WM8580_EXT_MCLK 4096000
#define SMDK_WM8580_EXT_VOICE 2048000
static unsigned long mclk_freq;
static unsigned long xtal_freq;
/*
* If MCLK clock directly gets from XTAL, we don't have to use PLL
* to make MCLK, but if XTAL clock source connects with other codec
* pin (like XTI), we should have to set codec's PLL to make MCLK.
* Because Samsung SoC does not support pcmcdclk output like I2S.
*/
static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int rfs, ret;
switch (params_rate(params)) {
case 8000:
break;
default:
printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
}
rfs = mclk_freq / params_rate(params) / 2;
if (mclk_freq == xtal_freq) {
ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
mclk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
WM8580_CLKSRC_MCLK);
if (ret < 0)
return ret;
} else {
ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
mclk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
WM8580_CLKSRC_PLLA);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
xtal_freq, mclk_freq);
if (ret < 0)
return ret;
}
/* Set PCM source clock on CPU */
ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
mclk_freq, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
/* Set SCLK_DIV for making bclk */
ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops smdk_wm8580_pcm_ops = {
.hw_params = smdk_wm8580_pcm_hw_params,
};
#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \
SND_SOC_DAIFMT_CBS_CFS)
static struct snd_soc_dai_link smdk_dai[] = {
{
.name = "WM8580 PAIF PCM RX",
.stream_name = "Playback",
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
.codec_name = "wm8580.0-001b",
.dai_fmt = SMDK_DAI_FMT,
.ops = &smdk_wm8580_pcm_ops,
}, {
.name = "WM8580 PAIF PCM TX",
.stream_name = "Capture",
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-pcm.0",
.codec_name = "wm8580.0-001b",
.dai_fmt = SMDK_DAI_FMT,
.ops = &smdk_wm8580_pcm_ops,
},
};
static struct snd_soc_card smdk_pcm = {
.name = "SMDK-PCM",
.owner = THIS_MODULE,
.dai_link = smdk_dai,
.num_links = 2,
};
/*
* After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1)
* is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4),
* 2.0484Mhz, directly with MCLK both Codec and SoC.
*/
static int snd_smdk_probe(struct platform_device *pdev)
{
int ret = 0;
xtal_freq = SMDK_WM8580_EXT_OSC;
mclk_freq = SMDK_WM8580_EXT_MCLK;
if (machine_is_smdkc110() || machine_is_smdkv210())
xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
smdk_pcm.dev = &pdev->dev;
ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
return ret;
}
static struct platform_driver snd_smdk_driver = {
.driver = {
.name = "samsung-smdk-pcm",
},
.probe = snd_smdk_probe,
};
module_platform_driver(snd_smdk_driver);
MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
MODULE_LICENSE("GPL");
/*
* smdk_wm9713.c -- SoC audio for SMDK
*
* Copyright 2010 Samsung Electronics Co. Ltd.
* Author: Jaswinder Singh Brar <jassisinghbrar@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
*/
#include <linux/module.h>
#include <sound/soc.h>
static struct snd_soc_card smdk;
/*
* Default CFG switch settings to use this driver:
*
* SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
* SMDKC100: Set CFG6 1-3 On, CFG7 1 On
* SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
* SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
* SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On
*/
/*
Playback (HeadPhone):-
$ amixer sset 'Headphone' unmute
$ amixer sset 'Right Headphone Out Mux' 'Headphone'
$ amixer sset 'Left Headphone Out Mux' 'Headphone'
$ amixer sset 'Right HP Mixer PCM' unmute
$ amixer sset 'Left HP Mixer PCM' unmute
Capture (LineIn):-
$ amixer sset 'Right Capture Source' 'Line'
$ amixer sset 'Left Capture Source' 'Line'
*/
static struct snd_soc_dai_link smdk_dai = {
.name = "AC97",
.stream_name = "AC97 PCM",
.platform_name = "samsung-ac97",
.cpu_dai_name = "samsung-ac97",
.codec_dai_name = "wm9713-hifi",
.codec_name = "wm9713-codec",
};
static struct snd_soc_card smdk = {
.name = "SMDK WM9713",
.owner = THIS_MODULE,
.dai_link = &smdk_dai,
.num_links = 1,
};
static struct platform_device *smdk_snd_wm9713_device;
static struct platform_device *smdk_snd_ac97_device;
static int __init smdk_init(void)
{
int ret;
smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
if (!smdk_snd_wm9713_device)
return -ENOMEM;
ret = platform_device_add(smdk_snd_wm9713_device);
if (ret)
goto err1;
smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
if (!smdk_snd_ac97_device) {
ret = -ENOMEM;
goto err2;
}
platform_set_drvdata(smdk_snd_ac97_device, &smdk);
ret = platform_device_add(smdk_snd_ac97_device);
if (ret)
goto err3;
return 0;
err3:
platform_device_put(smdk_snd_ac97_device);
err2:
platform_device_del(smdk_snd_wm9713_device);
err1:
platform_device_put(smdk_snd_wm9713_device);
return ret;
}
static void __exit smdk_exit(void)
{
platform_device_unregister(smdk_snd_ac97_device);
platform_device_unregister(smdk_snd_wm9713_device);
}
module_init(smdk_init);
module_exit(smdk_exit);
/* Module information */
MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com");
MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
*
* Authors: Inha Song <ideal.song@samsung.com>
* Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "i2s.h"
#include "../codecs/wm5110.h"
/*
* The source clock is XCLKOUT with its mux set to the external fixed rate
* oscillator (XXTI).
*/
#define MCLK_RATE 24000000U
#define TM2_DAI_AIF1 0
#define TM2_DAI_AIF2 1
struct tm2_machine_priv {
struct snd_soc_codec *codec;
unsigned int sysclk_rate;
struct gpio_desc *gpio_mic_bias;
};
static int tm2_start_sysclk(struct snd_soc_card *card)
{
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_codec *codec = priv->codec;
int ret;
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
priv->sysclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
priv->sysclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to start FLL1: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1,
priv->sysclk_rate,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret);
return ret;
}
return 0;
}
static int tm2_stop_sysclk(struct snd_soc_card *card)
{
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_codec *codec = priv->codec;
int ret;
ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1, 0, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret);
return ret;
}
return 0;
}
static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
switch (params_rate(params)) {
case 4000:
case 8000:
case 12000:
case 16000:
case 24000:
case 32000:
case 48000:
case 96000:
case 192000:
/* Highest possible SYSCLK frequency: 147.456MHz */
priv->sysclk_rate = 147456000U;
break;
case 11025:
case 22050:
case 44100:
case 88200:
case 176400:
/* Highest possible SYSCLK frequency: 135.4752 MHz */
priv->sysclk_rate = 135475200U;
break;
default:
dev_err(codec->dev, "Not supported sample rate: %d\n",
params_rate(params));
return -EINVAL;
}
return tm2_start_sysclk(rtd->card);
}
static struct snd_soc_ops tm2_aif1_ops = {
.hw_params = tm2_aif1_hw_params,
};
static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
unsigned int asyncclk_rate;
int ret;
switch (params_rate(params)) {
case 8000:
case 12000:
case 16000:
/* Highest possible ASYNCCLK frequency: 49.152MHz */
asyncclk_rate = 49152000U;
break;
case 11025:
/* Highest possible ASYNCCLK frequency: 45.1584 MHz */
asyncclk_rate = 45158400U;
break;
default:
dev_err(codec->dev, "Not supported sample rate: %d\n",
params_rate(params));
return -EINVAL;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
asyncclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2,
ARIZONA_FLL_SRC_MCLK1,
MCLK_RATE,
asyncclk_rate);
if (ret < 0) {
dev_err(codec->dev, "Failed to start FLL2: %d\n", ret);
return ret;
}
ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
ARIZONA_CLK_SRC_FLL2,
asyncclk_rate,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret);
return ret;
}
return 0;
}
static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
int ret;
/* disable FLL2 */
ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
0, 0);
if (ret < 0)
dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret);
return ret;
}
static struct snd_soc_ops tm2_aif2_ops = {
.hw_params = tm2_aif2_hw_params,
.hw_free = tm2_aif2_hw_free,
};
static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_card *card = w->dapm->card;
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
gpiod_set_value_cansleep(priv->gpio_mic_bias, 1);
break;
case SND_SOC_DAPM_POST_PMD:
gpiod_set_value_cansleep(priv->gpio_mic_bias, 0);
break;
}
return 0;
}
static int tm2_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
struct snd_soc_pcm_runtime *rtd;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
if (dapm->dev != rtd->codec_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
tm2_start_sysclk(card);
break;
case SND_SOC_BIAS_OFF:
tm2_stop_sysclk(card);
break;
default:
break;
}
return 0;
}
static struct snd_soc_aux_dev tm2_speaker_amp_dev;
static int tm2_late_probe(struct snd_soc_card *card)
{
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link_component dlc = { 0 };
unsigned int ch_map[] = { 0, 1 };
struct snd_soc_dai *amp_pdm_dai;
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *aif1_dai;
struct snd_soc_dai *aif2_dai;
int ret;
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
aif1_dai = rtd->codec_dai;
priv->codec = rtd->codec;
ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
if (ret < 0) {
dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret);
return ret;
}
rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name);
aif2_dai = rtd->codec_dai;
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
if (ret < 0) {
dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret);
return ret;
}
dlc.of_node = tm2_speaker_amp_dev.codec_of_node;
amp_pdm_dai = snd_soc_find_dai(&dlc);
if (!amp_pdm_dai)
return -ENODEV;
/* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map),
ch_map, 0, NULL);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16);
if (ret < 0)
return ret;
return 0;
}
static const struct snd_kcontrol_new tm2_controls[] = {
SOC_DAPM_PIN_SWITCH("HP"),
SOC_DAPM_PIN_SWITCH("SPK"),
SOC_DAPM_PIN_SWITCH("RCV"),
SOC_DAPM_PIN_SWITCH("VPS"),
SOC_DAPM_PIN_SWITCH("HDMI"),
SOC_DAPM_PIN_SWITCH("Main Mic"),
SOC_DAPM_PIN_SWITCH("Sub Mic"),
SOC_DAPM_PIN_SWITCH("Third Mic"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
SND_SOC_DAPM_HP("HP", NULL),
SND_SOC_DAPM_SPK("SPK", NULL),
SND_SOC_DAPM_SPK("RCV", NULL),
SND_SOC_DAPM_LINE("VPS", NULL),
SND_SOC_DAPM_LINE("HDMI", NULL),
SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias),
SND_SOC_DAPM_MIC("Sub Mic", NULL),
SND_SOC_DAPM_MIC("Third Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
static const struct snd_soc_component_driver tm2_component = {
.name = "tm2-audio",
};
static struct snd_soc_dai_driver tm2_ext_dai[] = {
{
.name = "Voice call",
.playback = {
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_48000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_48000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
},
{
.name = "Bluetooth",
.playback = {
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
.rate_max = 16000,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 16000,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
},
};
static struct snd_soc_dai_link tm2_dai_links[] = {
{
.name = "WM5110 AIF1",
.stream_name = "HiFi Primary",
.codec_dai_name = "wm5110-aif1",
.ops = &tm2_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
}, {
.name = "WM5110 Voice",
.stream_name = "Voice call",
.codec_dai_name = "wm5110-aif2",
.ops = &tm2_aif2_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.ignore_suspend = 1,
}, {
.name = "WM5110 BT",
.stream_name = "Bluetooth",
.codec_dai_name = "wm5110-aif3",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.ignore_suspend = 1,
}
};
static struct snd_soc_card tm2_card = {
.owner = THIS_MODULE,
.dai_link = tm2_dai_links,
.num_links = ARRAY_SIZE(tm2_dai_links),
.controls = tm2_controls,
.num_controls = ARRAY_SIZE(tm2_controls),
.dapm_widgets = tm2_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets),
.aux_dev = &tm2_speaker_amp_dev,
.num_aux_devs = 1,
.late_probe = tm2_late_probe,
.set_bias_level = tm2_set_bias_level,
};
static int tm2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct snd_soc_card *card = &tm2_card;
struct tm2_machine_priv *priv;
struct device_node *cpu_dai_node, *codec_dai_node;
int ret, i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
snd_soc_card_set_drvdata(card, priv);
card->dev = dev;
priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias",
GPIOF_OUT_INIT_LOW);
if (IS_ERR(priv->gpio_mic_bias)) {
dev_err(dev, "Failed to get mic bias gpio\n");
return PTR_ERR(priv->gpio_mic_bias);
}
ret = snd_soc_of_parse_card_name(card, "model");
if (ret < 0) {
dev_err(dev, "Card name is not specified\n");
return ret;
}
ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
if (ret < 0) {
dev_err(dev, "Audio routing is not specified or invalid\n");
return ret;
}
card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node,
"audio-amplifier", 0);
if (!card->aux_dev[0].codec_of_node) {
dev_err(dev, "audio-amplifier property invalid or missing\n");
return -EINVAL;
}
cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0);
if (!cpu_dai_node) {
dev_err(dev, "i2s-controllers property invalid or missing\n");
ret = -EINVAL;
goto amp_node_put;
}
codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0);
if (!codec_dai_node) {
dev_err(dev, "audio-codec property invalid or missing\n");
ret = -EINVAL;
goto cpu_dai_node_put;
}
for (i = 0; i < card->num_links; i++) {
card->dai_link[i].cpu_dai_name = NULL;
card->dai_link[i].cpu_name = NULL;
card->dai_link[i].platform_name = NULL;
card->dai_link[i].codec_of_node = codec_dai_node;
card->dai_link[i].cpu_of_node = cpu_dai_node;
card->dai_link[i].platform_of_node = cpu_dai_node;
}
ret = devm_snd_soc_register_component(dev, &tm2_component,
tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
if (ret < 0) {
dev_err(dev, "Failed to register component: %d\n", ret);
goto codec_dai_node_put;
}
ret = devm_snd_soc_register_card(dev, card);
if (ret < 0) {
dev_err(dev, "Failed to register card: %d\n", ret);
goto codec_dai_node_put;
}
codec_dai_node_put:
of_node_put(codec_dai_node);
cpu_dai_node_put:
of_node_put(cpu_dai_node);
amp_node_put:
of_node_put(card->aux_dev[0].codec_of_node);
return ret;
}
static int tm2_pm_prepare(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
return tm2_stop_sysclk(card);
}
static void tm2_pm_complete(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
tm2_start_sysclk(card);
}
const struct dev_pm_ops tm2_pm_ops = {
.prepare = tm2_pm_prepare,
.suspend = snd_soc_suspend,
.resume = snd_soc_resume,
.complete = tm2_pm_complete,
.freeze = snd_soc_suspend,
.thaw = snd_soc_resume,
.poweroff = snd_soc_poweroff,
.restore = snd_soc_resume,
};
static const struct of_device_id tm2_of_match[] = {
{ .compatible = "samsung,tm2-audio" },
{ },
};
MODULE_DEVICE_TABLE(of, tm2_of_match);
static struct platform_driver tm2_driver = {
.driver = {
.name = "tm2-audio",
.pm = &tm2_pm_ops,
.of_match_table = tm2_of_match,
},
.probe = tm2_probe,
};
module_platform_driver(tm2_driver);
MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>");
MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
MODULE_LICENSE("GPL v2");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment