summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Makefile5
-rw-r--r--sound/soc/codecs/cs42l52.c2
-rw-r--r--sound/soc/codecs/da9055.c22
-rw-r--r--sound/soc/codecs/twl6040.c8
-rw-r--r--sound/soc/codecs/wm2200.c3
-rw-r--r--sound/soc/codecs/wm8994.c20
-rw-r--r--sound/soc/codecs/wm8994.h1
-rw-r--r--sound/soc/omap/ams-delta.c63
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c2
-rw-r--r--sound/soc/omap/omap-dmic.c4
-rw-r--r--sound/soc/omap/omap-mcpdm.c9
-rw-r--r--sound/soc/omap/zoom2.c5
-rw-r--r--sound/soc/pxa/mmp-pcm.c2
-rw-r--r--sound/soc/samsung/bells.c4
-rw-r--r--sound/soc/sh/fsi.c456
-rw-r--r--sound/soc/soc-jack.c7
-rw-r--r--sound/soc/ux500/mop500.c17
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c8
18 files changed, 523 insertions, 115 deletions
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index bcbf1d00aa85..99f32f7c0692 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,8 +1,9 @@
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
-snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o
-obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
+ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
+snd-soc-core-objs += soc-dmaengine-pcm.o
+endif
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 61599298fb26..4d8db3685e96 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -763,7 +763,7 @@ static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
cs42l52->sysclk = freq;
} else {
- dev_err(codec->dev, "Invalid freq paramter\n");
+ dev_err(codec->dev, "Invalid freq parameter\n");
return -EINVAL;
}
return 0;
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 185d8dd36399..f379b085c392 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -178,6 +178,12 @@
#define DA9055_AIF_WORD_S24_LE (2 << 2)
#define DA9055_AIF_WORD_S32_LE (3 << 2)
+/* MIC_L_CTRL bit fields */
+#define DA9055_MIC_L_MUTE_EN (1 << 6)
+
+/* MIC_R_CTRL bit fields */
+#define DA9055_MIC_R_MUTE_EN (1 << 6)
+
/* MIXIN_L_CTRL bit fields */
#define DA9055_MIXIN_L_MIX_EN (1 << 3)
@@ -476,7 +482,7 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- u8 reg_val, adc_left, adc_right;
+ u8 reg_val, adc_left, adc_right, mic_left, mic_right;
int avg_left_data, avg_right_data, offset_l, offset_r;
if (ucontrol->value.integer.value[0]) {
@@ -485,6 +491,16 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
* offsets must be done first
*/
+ /* Save current values from Mic control registers */
+ mic_left = snd_soc_read(codec, DA9055_MIC_L_CTRL);
+ mic_right = snd_soc_read(codec, DA9055_MIC_R_CTRL);
+
+ /* Mute Mic PGA Left and Right */
+ snd_soc_update_bits(codec, DA9055_MIC_L_CTRL,
+ DA9055_MIC_L_MUTE_EN, DA9055_MIC_L_MUTE_EN);
+ snd_soc_update_bits(codec, DA9055_MIC_R_CTRL,
+ DA9055_MIC_R_MUTE_EN, DA9055_MIC_R_MUTE_EN);
+
/* Save current values from ADC control registers */
adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL);
adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL);
@@ -520,6 +536,10 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
/* Restore original values of ADC control registers */
snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left);
snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right);
+
+ /* Restore original values of Mic control registers */
+ snd_soc_write(codec, DA9055_MIC_L_CTRL, mic_left);
+ snd_soc_write(codec, DA9055_MIC_R_CTRL, mic_right);
}
return snd_soc_put_volsw(kcontrol, ucontrol);
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index e8f97af75928..00b85cc1b9a3 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -820,10 +820,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"VIBRA DAC", NULL, "Vibra Playback"},
/* ADC -> Stream mapping */
- {"ADC Left", NULL, "Legacy Capture"},
- {"ADC Left", NULL, "Capture"},
- {"ADC Right", NULL, "Legacy Capture"},
- {"ADC Right", NULL, "Capture"},
+ {"Legacy Capture" , NULL, "ADC Left"},
+ {"Capture", NULL, "ADC Left"},
+ {"Legacy Capture", NULL, "ADC Right"},
+ {"Capture" , NULL, "ADC Right"},
/* Capture path */
{"Analog Left Capture Route", "Headset Mic", "HSMIC"},
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index efa93dbb0191..eab64a193989 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1028,7 +1028,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
digital_tlv),
SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
- WM2200_SPK1R_MUTE_SHIFT, 1, 0),
+ WM2200_SPK1R_MUTE_SHIFT, 1, 1),
};
WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
@@ -2091,6 +2091,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
switch (wm2200->rev) {
case 0:
+ case 1:
ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
ARRAY_SIZE(wm2200_reva_patch));
if (ret != 0) {
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2b2dadc54dac..b2b2b37131bd 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1045,6 +1045,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = codec->control_data;
int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
int i;
@@ -1063,6 +1064,10 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ /* Don't enable timeslot 2 if not in use */
+ if (wm8994->channels[0] <= 2)
+ mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+
val = snd_soc_read(codec, WM8994_AIF1_CONTROL_1);
if ((val & WM8994_AIF1ADCL_SRC) &&
(val & WM8994_AIF1ADCR_SRC))
@@ -2687,7 +2692,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- bclk_rate = params_rate(params) * 4;
+ bclk_rate = params_rate(params);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
bclk_rate *= 16;
@@ -2708,6 +2713,17 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ wm8994->channels[id] = params_channels(params);
+ switch (params_channels(params)) {
+ case 1:
+ case 2:
+ bclk_rate *= 2;
+ break;
+ default:
+ bclk_rate *= 4;
+ break;
+ }
+
/* Try to find an appropriate sample rate; look for an exact match. */
for (i = 0; i < ARRAY_SIZE(srs); i++)
if (srs[i].rate == params_rate(params))
@@ -3706,7 +3722,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
} while (count--);
if (count == 0)
- dev_warn(codec->dev, "No impedence range reported for jack\n");
+ dev_warn(codec->dev, "No impedance range reported for jack\n");
#ifndef CONFIG_SND_SOC_WM8994_MODULE
trace_snd_soc_jack_irq(dev_name(codec->dev));
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index f142ec198db3..ccbce5791e95 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -77,6 +77,7 @@ struct wm8994_priv {
int sysclk_rate[2];
int mclk[2];
int aifclk[2];
+ int channels[2];
struct wm8994_fll_config fll[2], fll_suspend[2];
struct completion fll_locked[2];
bool fll_locked_irq;
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index dc0ee7626626..d8e96b2cd03e 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -575,56 +575,53 @@ static struct snd_soc_card ams_delta_audio_card = {
};
/* Module init/exit */
-static struct platform_device *ams_delta_audio_platform_device;
-static struct platform_device *cx20442_platform_device;
-
-static int __init ams_delta_module_init(void)
+static __devinit int ams_delta_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &ams_delta_audio_card;
int ret;
- if (!(machine_is_ams_delta()))
- return -ENODEV;
-
- ams_delta_audio_platform_device =
- platform_device_alloc("soc-audio", -1);
- if (!ams_delta_audio_platform_device)
- return -ENOMEM;
+ card->dev = &pdev->dev;
- platform_set_drvdata(ams_delta_audio_platform_device,
- &ams_delta_audio_card);
-
- ret = platform_device_add(ams_delta_audio_platform_device);
- if (ret)
- goto err;
-
- /*
- * Codec platform device could be registered from elsewhere (board?),
- * but I do it here as it makes sense only if used with the card.
- */
- cx20442_platform_device =
- platform_device_register_simple("cx20442-codec", -1, NULL, 0);
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ card->dev = NULL;
+ return ret;
+ }
return 0;
-err:
- platform_device_put(ams_delta_audio_platform_device);
- return ret;
}
-late_initcall(ams_delta_module_init);
-static void __exit ams_delta_module_exit(void)
+static int __devexit ams_delta_remove(struct platform_device *pdev)
{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
if (tty_unregister_ldisc(N_V253) != 0)
- dev_warn(&ams_delta_audio_platform_device->dev,
+ dev_warn(&pdev->dev,
"failed to unregister V253 line discipline\n");
snd_soc_jack_free_gpios(&ams_delta_hook_switch,
ARRAY_SIZE(ams_delta_hook_switch_gpios),
ams_delta_hook_switch_gpios);
- platform_device_unregister(cx20442_platform_device);
- platform_device_unregister(ams_delta_audio_platform_device);
+ snd_soc_unregister_card(card);
+ card->dev = NULL;
+ return 0;
}
-module_exit(ams_delta_module_exit);
+
+#define DRV_NAME "ams-delta-audio"
+
+static struct platform_driver ams_delta_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ams_delta_probe,
+ .remove = __devexit_p(ams_delta_remove),
+};
+
+module_platform_driver(ams_delta_driver);
MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 4a73ef3ae12f..a57a4e68dcc6 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -216,7 +216,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
- twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
+ twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator");
twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 68f2cd1a9206..5a6aeaf552a8 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -464,9 +464,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev)
mutex_init(&dmic->mutex);
- dmic->fclk = clk_get(dmic->dev, "dmic_fck");
+ dmic->fclk = clk_get(dmic->dev, "fck");
if (IS_ERR(dmic->fclk)) {
- dev_err(dmic->dev, "cant get dmic_fck\n");
+ dev_err(dmic->dev, "cant get fck\n");
return -ENODEV;
}
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index c02b001ee4b5..56965bb3275c 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -40,7 +40,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <plat/omap_hwmod.h>
#include "omap-mcpdm.h"
#include "omap-pcm.h"
@@ -260,13 +259,9 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
mutex_lock(&mcpdm->mutex);
if (!dai->active) {
- /* Enable watch dog for ES above ES 1.0 to avoid saturation */
- if (omap_rev() != OMAP4430_REV_ES1_0) {
- u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
- omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL,
- ctrl | MCPDM_WD_EN);
- }
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN);
omap_mcpdm_open_streams(mcpdm);
}
mutex_unlock(&mcpdm->mutex);
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 677b567935f8..1ff6bb9ade5c 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -21,15 +21,14 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/board-zoom.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/gpio-omap.h>
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 73ac5463c9e4..e834faf859fd 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -15,13 +15,13 @@
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-mmp_tdma.h>
#include <linux/platform_data/mmp_audio.h>
#include <sound/pxa2xx-lib.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <mach/sram.h>
#include <sound/dmaengine_pcm.h>
struct mmp_dma_data {
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 5dc10dfc0d42..b0d46d63d55e 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -212,7 +212,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = {
{
.name = "Sub",
.stream_name = "Sub",
- .cpu_dai_name = "wm5102-aif3",
+ .cpu_dai_name = "wm5110-aif3",
.codec_dai_name = "wm9081-hifi",
.codec_name = "wm9081.1-006c",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
@@ -247,7 +247,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = {
{
.name = "Sub",
.stream_name = "Sub",
- .cpu_dai_name = "wm5102-aif3",
+ .cpu_dai_name = "wm5110-aif3",
.codec_dai_name = "wm9081-hifi",
.codec_name = "wm9081.1-006c",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 5328ae5539f1..4a10e4d1bd43 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -20,7 +20,9 @@
#include <linux/sh_dma.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/workqueue.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <sound/sh_fsi.h>
/* PortA/PortB register */
@@ -188,6 +190,14 @@ typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
*/
/*
+ * FSI clock
+ *
+ * FSIxCLK [CPG] (ick) -------> |
+ * |-> FSI_DIV (div)-> FSI2
+ * FSIxCK [external] (xck) ---> |
+ */
+
+/*
* struct
*/
@@ -223,10 +233,24 @@ struct fsi_stream {
*/
struct dma_chan *chan;
struct sh_dmae_slave slave; /* see fsi_handler_init() */
- struct tasklet_struct tasklet;
+ struct work_struct work;
dma_addr_t dma;
};
+struct fsi_clk {
+ /* see [FSI clock] */
+ struct clk *own;
+ struct clk *xck;
+ struct clk *ick;
+ struct clk *div;
+ int (*set_rate)(struct device *dev,
+ struct fsi_priv *fsi,
+ unsigned long rate);
+
+ unsigned long rate;
+ unsigned int count;
+};
+
struct fsi_priv {
void __iomem *base;
struct fsi_master *master;
@@ -235,6 +259,8 @@ struct fsi_priv {
struct fsi_stream playback;
struct fsi_stream capture;
+ struct fsi_clk clock;
+
u32 fmt;
int chan_num:16;
@@ -716,14 +742,335 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
/*
* clock function
*/
+static int fsi_clk_init(struct device *dev,
+ struct fsi_priv *fsi,
+ int xck,
+ int ick,
+ int div,
+ int (*set_rate)(struct device *dev,
+ struct fsi_priv *fsi,
+ unsigned long rate))
+{
+ struct fsi_clk *clock = &fsi->clock;
+ int is_porta = fsi_is_port_a(fsi);
+
+ clock->xck = NULL;
+ clock->ick = NULL;
+ clock->div = NULL;
+ clock->rate = 0;
+ clock->count = 0;
+ clock->set_rate = set_rate;
+
+ clock->own = devm_clk_get(dev, NULL);
+ if (IS_ERR(clock->own))
+ return -EINVAL;
+
+ /* external clock */
+ if (xck) {
+ clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb");
+ if (IS_ERR(clock->xck)) {
+ dev_err(dev, "can't get xck clock\n");
+ return -EINVAL;
+ }
+ if (clock->xck == clock->own) {
+ dev_err(dev, "cpu doesn't support xck clock\n");
+ return -EINVAL;
+ }
+ }
+
+ /* FSIACLK/FSIBCLK */
+ if (ick) {
+ clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb");
+ if (IS_ERR(clock->ick)) {
+ dev_err(dev, "can't get ick clock\n");
+ return -EINVAL;
+ }
+ if (clock->ick == clock->own) {
+ dev_err(dev, "cpu doesn't support ick clock\n");
+ return -EINVAL;
+ }
+ }
+
+ /* FSI-DIV */
+ if (div) {
+ clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb");
+ if (IS_ERR(clock->div)) {
+ dev_err(dev, "can't get div clock\n");
+ return -EINVAL;
+ }
+ if (clock->div == clock->own) {
+ dev_err(dev, "cpu doens't support div clock\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0)
+static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate)
+{
+ fsi->clock.rate = rate;
+}
+
+static int fsi_clk_is_valid(struct fsi_priv *fsi)
+{
+ return fsi->clock.set_rate &&
+ fsi->clock.rate;
+}
+
+static int fsi_clk_enable(struct device *dev,
+ struct fsi_priv *fsi,
+ unsigned long rate)
+{
+ struct fsi_clk *clock = &fsi->clock;
+ int ret = -EINVAL;
+
+ if (!fsi_clk_is_valid(fsi))
+ return ret;
+
+ if (0 == clock->count) {
+ ret = clock->set_rate(dev, fsi, rate);
+ if (ret < 0) {
+ fsi_clk_invalid(fsi);
+ return ret;
+ }
+
+ if (clock->xck)
+ clk_enable(clock->xck);
+ if (clock->ick)
+ clk_enable(clock->ick);
+ if (clock->div)
+ clk_enable(clock->div);
+
+ clock->count++;
+ }
+
+ return ret;
+}
+
+static int fsi_clk_disable(struct device *dev,
+ struct fsi_priv *fsi)
+{
+ struct fsi_clk *clock = &fsi->clock;
+
+ if (!fsi_clk_is_valid(fsi))
+ return -EINVAL;
+
+ if (1 == clock->count--) {
+ if (clock->xck)
+ clk_disable(clock->xck);
+ if (clock->ick)
+ clk_disable(clock->ick);
+ if (clock->div)
+ clk_disable(clock->div);
+ }
+
+ return 0;
+}
+
+static int fsi_clk_set_ackbpf(struct device *dev,
+ struct fsi_priv *fsi,
+ int ackmd, int bpfmd)
+{
+ u32 data = 0;
+
+ /* check ackmd/bpfmd relationship */
+ if (bpfmd > ackmd) {
+ dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd);
+ return -EINVAL;
+ }
+
+ /* ACKMD */
+ switch (ackmd) {
+ case 512:
+ data |= (0x0 << 12);
+ break;
+ case 256:
+ data |= (0x1 << 12);
+ break;
+ case 128:
+ data |= (0x2 << 12);
+ break;
+ case 64:
+ data |= (0x3 << 12);
+ break;
+ case 32:
+ data |= (0x4 << 12);
+ break;
+ default:
+ dev_err(dev, "unsupported ackmd (%d)\n", ackmd);
+ return -EINVAL;
+ }
+
+ /* BPFMD */
+ switch (bpfmd) {
+ case 32:
+ data |= (0x0 << 8);
+ break;
+ case 64:
+ data |= (0x1 << 8);
+ break;
+ case 128:
+ data |= (0x2 << 8);
+ break;
+ case 256:
+ data |= (0x3 << 8);
+ break;
+ case 512:
+ data |= (0x4 << 8);
+ break;
+ case 16:
+ data |= (0x7 << 8);
+ break;
+ default:
+ dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd);
+
+ fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+ udelay(10);
+
+ return 0;
+}
+
+static int fsi_clk_set_rate_external(struct device *dev,
+ struct fsi_priv *fsi,
+ unsigned long rate)
+{
+ struct clk *xck = fsi->clock.xck;
+ struct clk *ick = fsi->clock.ick;
+ unsigned long xrate;
+ int ackmd, bpfmd;
+ int ret = 0;
+
+ /* check clock rate */
+ xrate = clk_get_rate(xck);
+ if (xrate % rate) {
+ dev_err(dev, "unsupported clock rate\n");
+ return -EINVAL;
+ }
+
+ clk_set_parent(ick, xck);
+ clk_set_rate(ick, xrate);
+
+ bpfmd = fsi->chan_num * 32;
+ ackmd = xrate / rate;
+
+ dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate);
+
+ ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
+ if (ret < 0)
+ dev_err(dev, "%s failed", __func__);
+
+ return ret;
+}
+
+static int fsi_clk_set_rate_cpg(struct device *dev,
+ struct fsi_priv *fsi,
+ unsigned long rate)
+{
+ struct clk *ick = fsi->clock.ick;
+ struct clk *div = fsi->clock.div;
+ unsigned long target = 0; /* 12288000 or 11289600 */
+ unsigned long actual, cout;
+ unsigned long diff, min;
+ unsigned long best_cout, best_act;
+ int adj;
+ int ackmd, bpfmd;
+ int ret = -EINVAL;
+
+ if (!(12288000 % rate))
+ target = 12288000;
+ if (!(11289600 % rate))
+ target = 11289600;
+ if (!target) {
+ dev_err(dev, "unsupported rate\n");
+ return ret;
+ }
+
+ bpfmd = fsi->chan_num * 32;
+ ackmd = target / rate;
+ ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
+ if (ret < 0) {
+ dev_err(dev, "%s failed", __func__);
+ return ret;
+ }
+
+ /*
+ * The clock flow is
+ *
+ * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec]
+ *
+ * But, it needs to find best match of CPG and FSI_DIV
+ * combination, since it is difficult to generate correct
+ * frequency of audio clock from ick clock only.
+ * Because ick is created from its parent clock.
+ *
+ * target = rate x [512/256/128/64]fs
+ * cout = round(target x adjustment)
+ * actual = cout / adjustment (by FSI-DIV) ~= target
+ * audio = actual
+ */
+ min = ~0;
+ best_cout = 0;
+ best_act = 0;
+ for (adj = 1; adj < 0xffff; adj++) {
+
+ cout = target * adj;
+ if (cout > 100000000) /* max clock = 100MHz */
+ break;
+
+ /* cout/actual audio clock */
+ cout = clk_round_rate(ick, cout);
+ actual = cout / adj;
+
+ /* find best frequency */
+ diff = abs(actual - target);
+ if (diff < min) {
+ min = diff;
+ best_cout = cout;
+ best_act = actual;
+ }
+ }
+
+ ret = clk_set_rate(ick, best_cout);
+ if (ret < 0) {
+ dev_err(dev, "ick clock failed\n");
+ return -EIO;
+ }
+
+ ret = clk_set_rate(div, clk_round_rate(div, best_act));
+ if (ret < 0) {
+ dev_err(dev, "div clock failed\n");
+ return -EIO;
+ }
+
+ dev_dbg(dev, "ick/div = %ld/%ld\n",
+ clk_get_rate(ick), clk_get_rate(div));
+
+ return ret;
+}
+
static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
long rate, int enable)
{
set_rate_func set_rate = fsi_get_info_set_rate(fsi);
int ret;
- if (!set_rate)
- return 0;
+ /*
+ * CAUTION
+ *
+ * set_rate will be deleted
+ */
+ if (!set_rate) {
+ if (enable)
+ return fsi_clk_enable(dev, fsi, rate);
+ else
+ return fsi_clk_disable(dev, fsi);
+ }
ret = set_rate(dev, rate, enable);
if (ret < 0) /* error */
@@ -1085,9 +1432,9 @@ static void fsi_dma_complete(void *data)
snd_pcm_period_elapsed(io->substream);
}
-static void fsi_dma_do_tasklet(unsigned long data)
+static void fsi_dma_do_work(struct work_struct *work)
{
- struct fsi_stream *io = (struct fsi_stream *)data;
+ struct fsi_stream *io = container_of(work, struct fsi_stream, work);
struct fsi_priv *fsi = fsi_stream_to_priv(io);
struct snd_soc_dai *dai;
struct dma_async_tx_descriptor *desc;
@@ -1129,7 +1476,7 @@ static void fsi_dma_do_tasklet(unsigned long data)
* FIXME
*
* In DMAEngine case, codec and FSI cannot be started simultaneously
- * since FSI is using tasklet.
+ * since FSI is using the scheduler work queue.
* Therefore, in capture case, probably FSI FIFO will have got
* overflow error in this point.
* in that case, DMA cannot start transfer until error was cleared.
@@ -1153,7 +1500,7 @@ static bool fsi_dma_filter(struct dma_chan *chan, void *param)
static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
{
- tasklet_schedule(&io->tasklet);
+ schedule_work(&io->work);
return 0;
}
@@ -1195,14 +1542,14 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev
return fsi_stream_probe(fsi, dev);
}
- tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
+ INIT_WORK(&io->work, fsi_dma_do_work);
return 0;
}
static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
{
- tasklet_kill(&io->tasklet);
+ cancel_work_sync(&io->work);
fsi_stream_stop(fsi, io);
@@ -1333,14 +1680,21 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
/* fifo init */
fsi_fifo_init(fsi, io, dev);
+ /* start master clock */
+ if (fsi_is_clk_master(fsi))
+ return fsi_set_master_clk(dev, fsi, fsi->rate, 1);
+
return 0;
}
-static void fsi_hw_shutdown(struct fsi_priv *fsi,
+static int fsi_hw_shutdown(struct fsi_priv *fsi,
struct device *dev)
{
+ /* stop master clock */
if (fsi_is_clk_master(fsi))
- fsi_set_master_clk(dev, fsi, fsi->rate, 0);
+ return fsi_set_master_clk(dev, fsi, fsi->rate, 0);
+
+ return 0;
}
static int fsi_dai_startup(struct snd_pcm_substream *substream,
@@ -1348,6 +1702,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
{
struct fsi_priv *fsi = fsi_get_priv(substream);
+ fsi_clk_invalid(fsi);
fsi->rate = 0;
return 0;
@@ -1358,6 +1713,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
{
struct fsi_priv *fsi = fsi_get_priv(substream);
+ fsi_clk_invalid(fsi);
fsi->rate = 0;
}
@@ -1371,13 +1727,16 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
fsi_stream_init(fsi, io, substream);
- fsi_hw_startup(fsi, io, dai->dev);
- ret = fsi_stream_transfer(io);
- if (0 == ret)
+ if (!ret)
+ ret = fsi_hw_startup(fsi, io, dai->dev);
+ if (!ret)
+ ret = fsi_stream_transfer(io);
+ if (!ret)
fsi_stream_start(fsi, io);
break;
case SNDRV_PCM_TRIGGER_STOP:
- fsi_hw_shutdown(fsi, dai->dev);
+ if (!ret)
+ ret = fsi_hw_shutdown(fsi, dai->dev);
fsi_stream_stop(fsi, io);
fsi_stream_quit(fsi, io);
break;
@@ -1436,9 +1795,25 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- if (fsi_is_clk_master(fsi) && !set_rate) {
- dev_err(dai->dev, "platform doesn't have set_rate\n");
- return -EINVAL;
+ if (fsi_is_clk_master(fsi)) {
+ /*
+ * CAUTION
+ *
+ * set_rate will be deleted
+ */
+ if (set_rate)
+ dev_warn(dai->dev, "set_rate will be removed soon\n");
+
+ switch (flags & SH_FSI_CLK_MASK) {
+ case SH_FSI_CLK_EXTERNAL:
+ fsi_clk_init(dai->dev, fsi, 1, 1, 0,
+ fsi_clk_set_rate_external);
+ break;
+ case SH_FSI_CLK_CPG:
+ fsi_clk_init(dai->dev, fsi, 0, 1, 1,
+ fsi_clk_set_rate_cpg);
+ break;
+ }
}
/* set format */
@@ -1461,19 +1836,13 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- long rate = params_rate(params);
- int ret;
-
- if (!fsi_is_clk_master(fsi))
- return 0;
- ret = fsi_set_master_clk(dai->dev, fsi, rate, 1);
- if (ret < 0)
- return ret;
-
- fsi->rate = rate;
+ if (fsi_is_clk_master(fsi)) {
+ fsi->rate = params_rate(params);
+ fsi_clk_valid(fsi, fsi->rate);
+ }
- return ret;
+ return 0;
}
static const struct snd_soc_dai_ops fsi_dai_ops = {
@@ -1497,7 +1866,7 @@ static struct snd_pcm_hardware fsi_pcm_hardware = {
.rates = FSI_RATES,
.rate_min = 8000,
.rate_max = 192000,
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
@@ -1585,14 +1954,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
- .channels_min = 1,
- .channels_max = 8,
+ .channels_min = 2,
+ .channels_max = 2,
},
.capture = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
- .channels_min = 1,
- .channels_max = 8,
+ .channels_min = 2,
+ .channels_max = 2,
},
.ops = &fsi_dai_ops,
},
@@ -1601,14 +1970,14 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
.playback = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
- .channels_min = 1,
- .channels_max = 8,
+ .channels_min = 2,
+ .channels_max = 2,
},
.capture = {
.rates = FSI_RATES,
.formats = FSI_FMTS,
- .channels_min = 1,
- .channels_max = 8,
+ .channels_min = 2,
+ .channels_max = 2,
},
.ops = &fsi_dai_ops,
},
@@ -1701,7 +2070,7 @@ static int fsi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
dev_set_drvdata(&pdev->dev, master);
- ret = request_irq(irq, &fsi_interrupt, 0,
+ ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0,
id_entry->name, master);
if (ret) {
dev_err(&pdev->dev, "irq request err\n");
@@ -1711,7 +2080,7 @@ static int fsi_probe(struct platform_device *pdev)
ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
if (ret < 0) {
dev_err(&pdev->dev, "cannot snd soc register\n");
- goto exit_free_irq;
+ goto exit_fsib;
}
ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai,
@@ -1725,8 +2094,6 @@ static int fsi_probe(struct platform_device *pdev)
exit_snd_soc:
snd_soc_unregister_platform(&pdev->dev);
-exit_free_irq:
- free_irq(irq, master);
exit_fsib:
pm_runtime_disable(&pdev->dev);
fsi_stream_remove(&master->fsib);
@@ -1742,7 +2109,6 @@ static int fsi_remove(struct platform_device *pdev)
master = dev_get_drvdata(&pdev->dev);
- free_irq(master->irq, master);
pm_runtime_disable(&pdev->dev);
snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
@@ -1773,10 +2139,6 @@ static void __fsi_resume(struct fsi_priv *fsi,
return;
fsi_hw_startup(fsi, io, dev);
-
- if (fsi_is_clk_master(fsi) && fsi->rate)
- fsi_set_master_clk(dev, fsi, fsi->rate, 1);
-
fsi_stream_start(fsi, io);
}
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index fa0fd8ddae90..1ab5fe04bfcc 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -22,7 +22,7 @@
/**
* snd_soc_jack_new - Create a new jack
- * @card: ASoC card
+ * @codec: ASoC codec
* @id: an identifying string for this jack
* @type: a bitmask of enum snd_jack_type values that can be detected by
* this jack
@@ -133,12 +133,13 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_add_zones);
/**
* snd_soc_jack_get_type - Based on the mic bias value, this function returns
- * the type of jack from the zones delcared in the jack type
+ * the type of jack from the zones declared in the jack type
*
+ * @jack: ASoC jack
* @micbias_voltage: mic bias voltage at adc channel when jack is plugged in
*
* Based on the mic bias value passed, this function helps identify
- * the type of jack from the already delcared jack zones
+ * the type of jack from the already declared jack zones
*/
int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage)
{
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 356611d9654d..54f7e25b6f7d 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -57,6 +57,20 @@ static struct snd_soc_card mop500_card = {
.num_links = ARRAY_SIZE(mop500_dai_links),
};
+static void mop500_of_node_put(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (mop500_dai_links[i].cpu_of_node)
+ of_node_put((struct device_node *)
+ mop500_dai_links[i].cpu_of_node);
+ if (mop500_dai_links[i].codec_of_node)
+ of_node_put((struct device_node *)
+ mop500_dai_links[i].codec_of_node);
+ }
+}
+
static int __devinit mop500_of_probe(struct platform_device *pdev,
struct device_node *np)
{
@@ -69,6 +83,7 @@ static int __devinit mop500_of_probe(struct platform_device *pdev,
if (!(msp_np[0] && msp_np[1] && codec_np)) {
dev_err(&pdev->dev, "Phandle missing or invalid\n");
+ mop500_of_node_put();
return -EINVAL;
}
@@ -83,6 +98,7 @@ static int __devinit mop500_of_probe(struct platform_device *pdev,
return 0;
}
+
static int __devinit mop500_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -128,6 +144,7 @@ static int __devexit mop500_remove(struct platform_device *pdev)
snd_soc_unregister_card(mop500_card);
mop500_ab8500_remove(mop500_card);
+ mop500_of_node_put();
return 0;
}
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index b7c996e77570..a26c6bf0a29b 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -18,6 +18,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/of.h>
#include <mach/hardware.h>
@@ -697,14 +698,11 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
platform_data = devm_kzalloc(&pdev->dev,
sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
if (!platform_data)
- ret = -ENOMEM;
+ return -ENOMEM;
}
} else
if (!platform_data)
- ret = -EINVAL;
-
- if (ret)
- goto err_res;
+ return -EINVAL;
dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
pdev->name, platform_data->id);