Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
July 2014
- 146 participants
- 288 discussions
Hello, I have developed a pcm ext plugin that applies some processing to the audio stream in the transfer callback.
My plugin works for a mono (1 channel) stream. I'd now like to expand it to support stereo data in the form of 2 channels interleaved. I can't find much information on how this works. I have a couple questions that I'd greatly appreciate if anyone could help with.
1) Is there any way in the 'SND_PCM_PLUGIN_DEFINE_FUNC' function that I can determine if the user application has opened the stream with 1 channel vs 2 channel?
2) I assume in the case of two channels my transfer function would need to: a)deinterleave the data from source so my processing routine can access it in a linear buffer and b) reinterleave the data before I copy it to destination. Is this correct? Is there more to it or things I am overlooking?
3) For IO-plugin I see there is a `SND_PCM_IOPLUG_HW_ACCESS` value I could use to restrict the stream type to `SND_PCM_ACCESS_RW_INTERLEAVED`. Does there exist a similar function for External PCM Plugin?
4)Is there some fundamental design idea here I am not grasping?
Thanks much!
Brandon
2
4
[alsa-devel] [PATCH] First attempt at a driver for the internal codec on the Allwinner A20.
by Jon Smirl 02 Jul '14
by Jon Smirl 02 Jul '14
02 Jul '14
First attempt at a driver for the internal codec on the Allwinner A20. This codec is a combination codec and DAI,
it is all on-chip.
So why don't I have a DMA buffer?
Any other hints to get this working would be appreciated.
[ 31.910394] pcm_sanity_check (null) (null)
[ 31.910415] ------------[ cut here ]------------
[ 31.910440] WARNING: CPU: 1 PID: 738 at sound/core/pcm_lib.c:2090 pcm_sanity_check+0x70/0x98()
[ 31.910448] Modules linked in: brcmfmac brcmutil
[ 31.910470] CPU: 1 PID: 738 Comm: aplay Not tainted 3.15.0+ #161
[ 31.910508] [<c001513c>] (unwind_backtrace) from [<c0011d08>] (show_stack+0x18/0x1c)
[ 31.910528] [<c0011d08>] (show_stack) from [<c0566934>] (dump_stack+0x78/0x94)
[ 31.910549] [<c0566934>] (dump_stack) from [<c00237c4>] (warn_slowpath_common+0x6c/0x90)
[ 31.910567] [<c00237c4>] (warn_slowpath_common) from [<c0023890>] (warn_slowpath_null+0x20/0x28)
[ 31.910585] [<c0023890>] (warn_slowpath_null) from [<c03f7e64>] (pcm_sanity_check+0x70/0x98)
[ 31.910602] [<c03f7e64>] (pcm_sanity_check) from [<c03faa08>] (snd_pcm_lib_write+0x1c/0x74)
[ 31.910619] [<c03faa08>] (snd_pcm_lib_write) from [<c03f6400>] (snd_pcm_playback_ioctl1+0x3c8/0x4a8)
[ 31.910637] [<c03f6400>] (snd_pcm_playback_ioctl1) from [<c013762c>] (do_vfs_ioctl+0x4d4/0x594)
[ 31.910653] [<c013762c>] (do_vfs_ioctl) from [<c0137740>] (SyS_ioctl+0x54/0x7c)
[ 31.910668] [<c0137740>] (SyS_ioctl) from [<c000e420>] (ret_fast_syscall+0x0/0x30)
[ 31.910677] ---[ end trace 86fcd83010b5b5b5 ]---
---
sound/soc/sunxi/sunxi_codec_main.c | 687 ++++++++++++++++++++++++++++++++++++
1 file changed, 687 insertions(+)
create mode 100644 sound/soc/sunxi/sunxi_codec_main.c
diff --git a/sound/soc/sunxi/sunxi_codec_main.c b/sound/soc/sunxi/sunxi_codec_main.c
new file mode 100644
index 0000000..4070bfe
--- /dev/null
+++ b/sound/soc/sunxi/sunxi_codec_main.c
@@ -0,0 +1,687 @@
+/*
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+//Codec Register
+#define SUNXI_DAC_DPC (0x00)
+#define SUNXI_DAC_FIFOC (0x04)
+#define SUNXI_DAC_FIFOS (0x08)
+#define SUNXI_DAC_TXDATA (0x0c)
+#define SUNXI_DAC_ACTL (0x10)
+#define SUNXI_DAC_TUNE (0x14)
+#define SUNXI_DAC_DEBUG (0x18)
+#define SUNXI_ADC_FIFOC (0x1c)
+#define SUNXI_ADC_FIFOS (0x20)
+#define SUNXI_ADC_RXDATA (0x24)
+#define SUNXI_ADC_ACTL (0x28)
+#define SUNXI_ADC_DEBUG (0x2c)
+#define SUNXI_DAC_TXCNT (0x30)
+#define SUNXI_ADC_RXCNT (0x34)
+#define SUNXI_BIAS_CRT (0x38)
+#define SUNXI_MIC_CRT (0x3c)
+#define SUNXI_CODEC_REGS_NUM (13)
+
+#define DAIFMT_16BITS (16)
+#define DAIFMT_20BITS (20)
+
+#define DAIFMT_BS_MASK (~(1<<16)) //FIFO big small mode mask
+#define DAIFMT_BITS_MASK (~(1<<5)) //FIFO Bits select mask,not used yet.
+#define SAMPLE_RATE_MASK (~(7<<29)) //Sample Rate slect mask
+
+#define DAC_EN (31)
+#define DIGITAL_VOL (12)
+//For CODEC OLD VERSION
+#define DAC_VERSION (23)
+
+#define DAC_CHANNEL (6)
+#define LAST_SE (26)
+#define TX_FIFO_MODE (24)
+#define DRA_LEVEL (21)
+#define TX_TRI_LEVEL (8)
+#define DAC_MODE (6) //not used yet
+#define TASR (5) //not used yet
+#define DAC_DRQ (4)
+#define DAC_FIFO_FLUSH (0)
+
+#define VOLUME (0)
+#define PA_MUTE (6)
+#define MIXPAS (7)
+#define DACPAS (8)
+#define MIXEN (29)
+#define DACAEN_L (30)
+#define DACAEN_R (31)
+
+#define ADC_DIG_EN (28)
+#define RX_FIFO_MODE (24)
+#define RX_TRI_LEVEL (8)
+#define ADC_MODE (7)
+#define RASR (6)
+#define ADC_DRQ (4)
+#define ADC_FIFO_FLUSH (0)
+
+#define ADC_LF_EN (31)
+#define ADC_RI_EN (30)
+#define ADC_EN (30)
+#define MIC1_EN (29)
+#define MIC2_EN (28)
+#define VMIC_EN (27)
+#define MIC_GAIN (25)
+#define ADC_SELECT (17)
+#define PA_ENABLE (4)
+#define HP_DIRECT (3)
+
+
+enum sunxi_device_id {SUN4A, SUN4I, SUN5I, SUN7I};
+
+struct sunxi_priv {
+ struct regmap *regmap;
+ int irq;
+ struct clk *clk_apb, *clk_pll2, *clk_module;
+
+ enum sunxi_device_id id;
+
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+};
+
+static int codec_play_start(struct sunxi_priv *priv)
+{
+#ifdef JDS
+ if (gpio_pa_shutdown)
+ gpio_write_one_pin_value(gpio_pa_shutdown, 1, "audio_pa_ctrl");
+#endif
+ //flush TX FIFO
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << DAC_FIFO_FLUSH, 0x1 << DAC_FIFO_FLUSH);
+ //enable dac drq
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << DAC_DRQ, 0x1 << DAC_DRQ);
+ return 0;
+}
+
+static int codec_play_stop(struct sunxi_priv *priv)
+{
+ //pa mute
+#ifdef JDS
+ if (gpio_pa_shutdown)
+ gpio_write_one_pin_value(gpio_pa_shutdown, 0, "audio_pa_ctrl");
+#endif
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << PA_MUTE, 0x0 << PA_MUTE);
+ mdelay(5);
+ //disable dac drq
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << DAC_DRQ, 0x0 << DAC_DRQ);
+ //pa mute
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << PA_MUTE, 0x0 << PA_MUTE);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << DACAEN_L, 0x0 << DACAEN_L);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << DACAEN_R, 0x0 << DACAEN_R);
+ return 0;
+}
+
+static int codec_capture_start(struct sunxi_priv *priv)
+{
+ //enable adc drq
+#ifdef JDS
+ if (gpio_pa_shutdown)
+ gpio_write_one_pin_value(gpio_pa_shutdown, 1, "audio_pa_ctrl");
+#endif
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_DRQ, 0x1 << ADC_DRQ);
+ return 0;
+}
+
+static int codec_capture_stop(struct sunxi_priv *priv)
+{
+ //disable adc drq
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_DRQ, 0x0 << ADC_DRQ);
+ //enable mic1 pa
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << MIC1_EN, 0x0 << MIC1_EN);
+ //enable VMIC
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << VMIC_EN, 0x0 << VMIC_EN);
+ if (priv->id == SUN7I) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_TUNE, 0x3 << 8, 0x0 << 8);
+ }
+ //enable adc digital
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_DIG_EN, 0x0 << ADC_DIG_EN);
+ //set RX FIFO mode
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << RX_FIFO_MODE, 0x0 << RX_FIFO_MODE);
+ //flush RX FIFO
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_FIFO_FLUSH, 0x0 << ADC_FIFO_FLUSH);
+ //enable adc1 analog
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << ADC_EN, 0x0 << ADC_EN);
+ return 0;
+}
+
+static int sunxi_codec_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ printk("JDS - sunxi_codec_trigger cmd %d\n", cmd);
+ 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)
+ codec_capture_start(priv);
+ else
+ codec_play_start(priv);
+ break; break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ codec_capture_stop(priv);
+ else
+ codec_play_stop(priv);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sunxi_codec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ printk("JDS - sunxi_codec_prepare\n");
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
+ regmap_update_bits(priv->regmap, SUNXI_DAC_DPC, 0x1 << DAC_EN, 0x1 << DAC_EN);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << DAC_FIFO_FLUSH, 0x1 << DAC_FIFO_FLUSH);
+ //set TX FIFO send drq level
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0xf << TX_TRI_LEVEL, 0xf << TX_TRI_LEVEL);
+ if (substream->runtime->rate > 32000) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << 28, 0x0 << 28);
+ } else {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << 28, 0x1 << 28);
+ }
+ //set TX FIFO MODE
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << TX_FIFO_MODE, 0x1 << TX_FIFO_MODE);
+ //send last sample when dac fifo under run
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << LAST_SE, 0x0 << LAST_SE);
+ //enable dac analog
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << DACAEN_L, 0x1 << DACAEN_L);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << DACAEN_R, 0x1 << DACAEN_R);
+ //enable dac to pa
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x1 << DACPAS, 0x1 << DACPAS);
+ } else {
+ //enable mic1 pa
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << MIC1_EN, 0x1 << MIC1_EN);
+ //mic1 gain 32dB
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << 25, 0x1 << 25);
+ //enable VMIC
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << VMIC_EN, 0x1 << VMIC_EN);
+
+ if (priv->id == SUN7I) {
+ /* boost up record effect */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_TUNE, 0x3 << 8, 0x1 << 8);
+ }
+
+ //enable adc digital
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_DIG_EN, 0x1 << ADC_DIG_EN);
+ //set RX FIFO mode
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << RX_FIFO_MODE, 0x1 << RX_FIFO_MODE);
+ //flush RX FIFO
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << ADC_FIFO_FLUSH, 0x1 << ADC_FIFO_FLUSH);
+ //set RX FIFO rec drq level
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0xf << RX_TRI_LEVEL, 0x7 << RX_TRI_LEVEL);
+ //enable adc1 analog
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << ADC_EN, 0x3 << ADC_EN);
+ }
+ return 0;
+}
+
+static int sunxi_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+ unsigned int rate = params_rate(params);
+
+ printk("CLK - sunxi_codec_hw_params substream %p runtime %p\n", substream, rtd);
+ switch (params_rate(params)) {
+ case 44100:
+ case 22050:
+ case 11025:
+ default:
+ clk_set_rate(priv->clk_pll2, 22579200);
+ clk_set_rate(priv->clk_module, 22579200);
+ break;
+ case 192000:
+ case 96000:
+ case 48000:
+ case 32000:
+ case 24000:
+ case 16000:
+ case 12000:
+ case 8000:
+ clk_set_rate(priv->clk_pll2, 24576000);
+ clk_set_rate(priv->clk_module, 24576000);
+ break;
+ }
+
+ switch (params_rate(params)) {
+ default:
+ case 44100:
+ rate = 0;
+ break;
+ case 22050:
+ rate = 2;
+ break;
+ case 11025:
+ rate = 4;
+ break;
+ case 192000:
+ rate = 6;
+ break;
+ case 96000:
+ rate = 7;
+ break;
+ case 48000:
+ rate = 0;
+ break;
+ case 32000:
+ rate = 1;
+ break;
+ case 24000:
+ rate = 2;
+ break;
+ case 16000:
+ rate = 3;
+ break;
+ case 12000:
+ rate = 4;
+ break;
+ case 8000:
+ rate = 5;
+ break;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 7 << 29, rate << 29);
+ if (substream->runtime->channels == 1)
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << 6, 1 << 6);
+ else
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << 6, 0 << 6);
+ } else {
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 7 << 29, rate << 29);
+ if (substream->runtime->channels == 1)
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 1 << 7, 1 << 7);
+ else
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 1 << 7, 0 << 7);
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new sun7i_dac_ctls[] = {
+ /*SUNXI_DAC_ACTL = 0x10,PAVOL*/
+ SOC_SINGLE("Master Playback Volume", SUNXI_DAC_ACTL, 0, 0x3f, 0),
+ SOC_SINGLE("Playback Switch", SUNXI_DAC_ACTL, 6, 1, 0), //全局输出开关
+ SOC_SINGLE("FmL Switch", SUNXI_DAC_ACTL, 17, 1, 0), //Fm左开关
+ SOC_SINGLE("FmR Switch", SUNXI_DAC_ACTL, 16, 1, 0), //Fm右开关
+ SOC_SINGLE("LineL Switch", SUNXI_DAC_ACTL, 19, 1, 0), //Line左开关
+ SOC_SINGLE("LineR Switch", SUNXI_DAC_ACTL, 18, 1, 0), //Line右开关
+ SOC_SINGLE("Ldac Left Mixer", SUNXI_DAC_ACTL, 15, 1, 0),
+ SOC_SINGLE("Rdac Right Mixer", SUNXI_DAC_ACTL, 14, 1, 0),
+ SOC_SINGLE("Ldac Right Mixer", SUNXI_DAC_ACTL, 13, 1, 0),
+ SOC_SINGLE("Mic Input Mux", SUNXI_DAC_ACTL, 9, 15, 0), //from bit 9 to bit 12.Mic(麦克风)输入静音
+ SOC_SINGLE("MIC output volume", SUNXI_DAC_ACTL, 20, 7, 0),
+ /* FM Input to output mixer Gain Control
+ * From -4.5db to 6db,1.5db/step,default is 0db
+ * -4.5db:0x0,-3.0db:0x1,-1.5db:0x2,0db:0x3
+ * 1.5db:0x4,3.0db:0x5,4.5db:0x6,6db:0x7
+ */
+ SOC_SINGLE("Fm output Volume", SUNXI_DAC_ACTL, 23, 7, 0),
+ /* Line-in gain stage to output mixer Gain Control
+ * 0:-1.5db,1:0db
+ */
+ SOC_SINGLE("Line output Volume", SUNXI_DAC_ACTL, 26, 1, 0),
+
+ SOC_SINGLE("Master Capture Mute", SUNXI_ADC_ACTL, 4, 1, 0),
+ SOC_SINGLE("Right Capture Mute", SUNXI_ADC_ACTL, 31, 1, 0),
+ SOC_SINGLE("Left Capture Mute", SUNXI_ADC_ACTL, 30, 1, 0),
+ SOC_SINGLE("Linein Pre-AMP", SUNXI_ADC_ACTL, 13, 7, 0),
+ SOC_SINGLE("LINEIN APM Volume", SUNXI_MIC_CRT, 13, 0x7, 0),
+ /* ADC Input Gain Control, capture volume
+ * 000:-4.5db,001:-3db,010:-1.5db,011:0db,100:1.5db,101:3db,110:4.5db,111:6db
+ */
+ SOC_SINGLE("Capture Volume", SUNXI_ADC_ACTL, 20, 7, 0),
+ /*
+ * MIC2 pre-amplifier Gain Control
+ * 00:0db,01:35db,10:38db,11:41db
+ */
+ SOC_SINGLE("MicL Volume", SUNXI_ADC_ACTL, 25, 3, 0), //mic左音量
+ SOC_SINGLE("MicR Volume", SUNXI_ADC_ACTL, 23, 3, 0), //mic右音量
+ SOC_SINGLE("Mic2 Boost", SUNXI_ADC_ACTL, 29, 1, 0),
+ SOC_SINGLE("Mic1 Boost", SUNXI_ADC_ACTL, 28, 1, 0),
+ SOC_SINGLE("Mic Power", SUNXI_ADC_ACTL, 27, 1, 0),
+ SOC_SINGLE("ADC Input Mux", SUNXI_ADC_ACTL, 17, 7, 0), //ADC输入静音
+ SOC_SINGLE("Mic2 gain Volume", SUNXI_MIC_CRT, 26, 7, 0),
+ /*
+ * MIC1 pre-amplifier Gain Control
+ * 00:0db,01:35db,10:38db,11:41db
+ */
+ SOC_SINGLE("Mic1 gain Volume", SUNXI_MIC_CRT, 29, 3, 0),
+};
+
+
+static int sunxi_codec_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ printk("CLK - sunxi_codec_dai_probe %p\n", priv);
+ snd_soc_dai_init_dma_data(dai, &priv->playback_dma_data, &priv->capture_dma_data);
+
+ return 0;
+}
+
+static int sunxi_codec_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ int ret;
+ printk("JDS - CLK sunxi_codec_startup %p %p\n", codec, priv->clk_module);
+ ret = clk_prepare_enable(priv->clk_module);
+ if (ret)
+ return ret;
+
+ printk("JDS - sunxi_codec_startup - ok\n");
+ return 0;
+}
+
+static void sunxi_codec_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ printk("JDS - sunxi_codec_shutdown\n");
+ clk_disable_unprepare(priv->clk_module);
+}
+
+static const struct snd_soc_dai_ops sunxi_codec_dai_ops = {
+ .startup = sunxi_codec_startup,
+ .shutdown = sunxi_codec_shutdown,
+ .trigger = sunxi_codec_trigger,
+ .hw_params = sunxi_codec_hw_params,
+ .prepare = sunxi_codec_prepare,
+};
+
+static struct snd_soc_dai_driver sunxi_codec_dai = {
+ .probe = sunxi_codec_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_22050| SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 |SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &sunxi_codec_dai_ops,
+};
+
+static const struct snd_soc_component_driver sunxi_codec_component = {
+ .name = "sunxi-codec",
+};
+
+static const struct regmap_config sunxi_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUNXI_MIC_CRT,
+};
+
+static const struct snd_soc_dapm_widget codec_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("Mic Bias"),
+ SND_SOC_DAPM_OUTPUT("HP_OUT"),
+ SND_SOC_DAPM_INPUT("MIC_IN"),
+ SND_SOC_DAPM_INPUT("LINE_IN"),
+};
+
+static struct snd_soc_dai_link cdc_dai = {
+ .name = "cdc",
+ .stream_name = "CDC PCM",
+ .codec_dai_name = "sunxi-codec-dai",
+ .cpu_dai_name = "1c22c00.codec",
+ .codec_name = "1c22c00.codec",
+ //.init = tegra_wm8903_init,
+ //.ops = &tegra_wm8903_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S,
+};
+
+static struct snd_soc_card snd_soc_sunxi_codec = {
+ .name = "sunxi-codec",
+ .owner = THIS_MODULE,
+ .dai_link = &cdc_dai,
+ .num_links = 1,
+
+ .fully_routed = true,
+};
+
+static struct snd_soc_codec_driver dummy_codec = {
+ .controls = sun7i_dac_ctls,
+ .num_controls = ARRAY_SIZE(sun7i_dac_ctls),
+ .dapm_widgets = codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(codec_dapm_widgets),
+};
+
+#define STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+static struct snd_soc_dai_driver dummy_dai = {
+ .name = "sunxi-codec-dai",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+};
+
+static const struct of_device_id sunxi_codec_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10a-codec", .data = (void *)SUN4A},
+ { .compatible = "allwinner,sun4i-a10-codec", .data = (void *)SUN4I},
+ { .compatible = "allwinner,sun5i-a13-codec", .data = (void *)SUN5I},
+ { .compatible = "allwinner,sun7i-a20-codec", .data = (void *)SUN7I},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sunxi_codec_of_match);
+
+static int sunxi_codec_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &snd_soc_sunxi_codec;
+ const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct sunxi_priv *priv;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ if (!of_device_is_available(np))
+ return -ENODEV;
+
+ of_id = of_match_device(sunxi_codec_of_match, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, priv);
+
+ priv->id = (int)of_id->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sunxi_codec_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->irq = irq_of_parse_and_map(np, 0);
+ if (!priv->irq) {
+ dev_err(dev, "no irq for node %s\n", np->full_name);
+ return -ENXIO;
+ }
+
+ /* Clock */
+ priv->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(priv->clk_apb)) {
+ dev_err(dev, "failed to get apb clock.\n");
+ return PTR_ERR(priv->clk_apb);
+ }
+ priv->clk_pll2 = devm_clk_get(dev, "pll2");
+ if (IS_ERR(priv->clk_pll2)) {
+ dev_err(dev, "failed to get pll2 clock.\n");
+ return PTR_ERR(priv->clk_pll2);
+ }
+ priv->clk_module = devm_clk_get(dev, "codec");
+ if (IS_ERR(priv->clk_module)) {
+ dev_err(dev, "failed to get codec clock.\n");
+ return PTR_ERR(priv->clk_module);
+ }
+ printk("CLK = card %p priv %p priv->clk_module %p\n", card, priv, priv->clk_module);
+
+ ret = clk_set_rate(priv->clk_pll2, 24576000);
+ if (ret) {
+ dev_err(dev, "set codec base clock rate failed!\n");
+ return ret;
+ }
+ if (clk_prepare_enable(priv->clk_pll2)) {
+ dev_err(dev, "try to enable clk_pll2 failed\n");
+ return -EINVAL;
+ }
+ if (clk_prepare_enable(priv->clk_apb)) {
+ dev_err(dev, "try to enable clk_apb failed\n");
+ return -EINVAL;
+ }
+
+ priv->playback_dma_data.addr = res->start + SUNXI_DAC_TXDATA;
+ priv->playback_dma_data.maxburst = 4;
+ priv->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ priv->capture_dma_data.addr = res->start + SUNXI_ADC_RXDATA;
+ priv->capture_dma_data.maxburst = 4;
+ priv->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ ret = snd_soc_register_codec(&pdev->dev, &dummy_codec, &dummy_dai, 1);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &sunxi_codec_component, &sunxi_codec_dai, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = snd_soc_of_parse_audio_routing(card, "routing");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ goto err_fini_utils;
+ }
+
+ return 0;
+
+err_fini_utils:
+err:
+err_clk_disable:
+ clk_disable_unprepare(priv->clk_module);
+ clk_disable_unprepare(priv->clk_apb);
+ clk_disable_unprepare(priv->clk_pll2);
+ return ret;
+}
+
+static int sunxi_codec_dev_remove(struct platform_device *pdev)
+{
+ struct sunxi_priv *priv = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(priv->clk_module);
+ clk_disable_unprepare(priv->clk_apb);
+ clk_disable_unprepare(priv->clk_pll2);
+
+ return 0;
+}
+
+static struct platform_driver sunxi_codec_driver = {
+ .driver = {
+ .name = "sunxi-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = sunxi_codec_of_match,
+ },
+ .probe = sunxi_codec_probe,
+ .remove = sunxi_codec_dev_remove,
+};
+module_platform_driver(sunxi_codec_driver);
+
+MODULE_ALIAS("platform:sunxi-codec");
+MODULE_DESCRIPTION("sunxi CODEC ALSA codec driver");
+MODULE_AUTHOR("software");
+MODULE_LICENSE("GPL v2");
+
3
2
[alsa-devel] [PATCH 0/4] ALSA/dmaengine: Fix 3 bytes physical sample support
by Peter Ujfalusi 02 Jul '14
by Peter Ujfalusi 02 Jul '14
02 Jul '14
Hi,
I have noticed while switching the daVinci audio to dmaengine_pcm that the _3LE
and _3BE support is not working correctly via dmaengine_pcm:
In case of _3LE/_3BE formats the samples are stored in 3 consecutive bytes
without padding it to 4 bytes. This means that the DMA needs to be able to
support 3 bytes word length in order to read/write the samples from memory
correctly. Originally the code treated 24 bits physical length samples as
they were 32 bits which leads to corruption when playing or recording audio.
To fix the support for 3 bytes physical samples the dma driver also need to have
support for such data arrangement. eDMA does have support for it in HW and the
legacy davinci-pcm platform driver w/o dmaengine was able to support such
formats.
First step is to add DMA_SLAVE_BUSWIDTH_3_BYTES to dma_slave_buswidth for
engines and users to select 3 bytes as bus width.
Followed by:
In snd_dmaengine_pcm_open() we should check the slave_caps of the dma if it
supports DMA_SLAVE_BUSWIDTH_3_BYTES. Based on this information we initialize
the runtime->hw.formats: if DMA_SLAVE_BUSWIDTH_3_BYTES is not supported or
the slave_caps is not provided by the driver we mask out the 24 bits
physical width sample formats so they will be not available for user space
to pick. If the DMA_SLAVE_BUSWIDTH_3_BYTES is supported _3LE/_3BE formats
will not be masked so later on they can be valid if both CPU and codec dai
supports them.
Regards,
Peter
---
Peter Ujfalusi (4):
dma: Support for 3 bytes word size
dma: edma: Declare DMA_SLAVE_BUSWIDTH_3_BYTES as supported buswidth
ALSA: pcm_dmaengine: Use the available wrapper to get physical width
ALSA: pcm_dmaengine: Correct support for 3 physical bytes samples
drivers/dma/edma.c | 1 +
include/linux/dmaengine.h | 1 +
sound/core/pcm_dmaengine.c | 41 +++++++++++++++++++++++++++++++++++++++--
3 files changed, 41 insertions(+), 2 deletions(-)
--
2.0.0
2
8
Re: [alsa-devel] [Alsa-user] Constant delay between starting a playback and a capture stream
by Max Schmidt 02 Jul '14
by Max Schmidt 02 Jul '14
02 Jul '14
Hi,
just for correction if someone will ever read my question again:
of course it's microseconds and not milliseconds
Sorry for the disturbance and regards
1
0
[alsa-devel] [PATCH 1/1] ice1712: Aligning definitions in header file
by Konstantinos Tsimpoukas 02 Jul '14
by Konstantinos Tsimpoukas 02 Jul '14
02 Jul '14
Aligning #defines in ice1712.h file.
Signed-off-by: Konstantinos Tsimpoukas <kostaslinuxxx(a)gmail.com>
---
sound/pci/ice1712/ice1712.h | 84 ++++++++++++++++++++++-----------------------
1 file changed, 42 insertions(+), 42 deletions(-)
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index b209fc3..f88800a 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -41,18 +41,18 @@
#define ICEREG(ice, x) ((ice)->port + ICE1712_REG_##x)
#define ICE1712_REG_CONTROL 0x00 /* byte */
-#define ICE1712_RESET 0x80 /* reset whole chip */
-#define ICE1712_SERR_LEVEL 0x04 /* SERR# level otherwise edge */
-#define ICE1712_NATIVE 0x01 /* native mode otherwise SB */
+#define ICE1712_RESET 0x80 /* reset whole chip */
+#define ICE1712_SERR_LEVEL 0x04 /* SERR# level otherwise edge */
+#define ICE1712_NATIVE 0x01 /* native mode otherwise SB */
#define ICE1712_REG_IRQMASK 0x01 /* byte */
-#define ICE1712_IRQ_MPU1 0x80
-#define ICE1712_IRQ_TIMER 0x40
-#define ICE1712_IRQ_MPU2 0x20
-#define ICE1712_IRQ_PROPCM 0x10
-#define ICE1712_IRQ_FM 0x08 /* FM/MIDI - legacy */
-#define ICE1712_IRQ_PBKDS 0x04 /* playback DS channels */
-#define ICE1712_IRQ_CONCAP 0x02 /* consumer capture */
-#define ICE1712_IRQ_CONPBK 0x01 /* consumer playback */
+#define ICE1712_IRQ_MPU1 0x80
+#define ICE1712_IRQ_TIMER 0x40
+#define ICE1712_IRQ_MPU2 0x20
+#define ICE1712_IRQ_PROPCM 0x10
+#define ICE1712_IRQ_FM 0x08 /* FM/MIDI - legacy */
+#define ICE1712_IRQ_PBKDS 0x04 /* playback DS channels */
+#define ICE1712_IRQ_CONCAP 0x02 /* consumer capture */
+#define ICE1712_IRQ_CONPBK 0x01 /* consumer playback */
#define ICE1712_REG_IRQSTAT 0x02 /* byte */
/* look to ICE1712_IRQ_* */
#define ICE1712_REG_INDEX 0x03 /* byte - indirect CCIxx regs */
@@ -62,23 +62,23 @@
#define ICE1712_REG_NMI_INDEX 0x07 /* byte */
#define ICE1712_REG_AC97_INDEX 0x08 /* byte */
#define ICE1712_REG_AC97_CMD 0x09 /* byte */
-#define ICE1712_AC97_COLD 0x80 /* cold reset */
-#define ICE1712_AC97_WARM 0x40 /* warm reset */
-#define ICE1712_AC97_WRITE 0x20 /* W: write, R: write in progress */
-#define ICE1712_AC97_READ 0x10 /* W: read, R: read in progress */
-#define ICE1712_AC97_READY 0x08 /* codec ready status bit */
-#define ICE1712_AC97_PBK_VSR 0x02 /* playback VSR */
-#define ICE1712_AC97_CAP_VSR 0x01 /* capture VSR */
+#define ICE1712_AC97_COLD 0x80 /* cold reset */
+#define ICE1712_AC97_WARM 0x40 /* warm reset */
+#define ICE1712_AC97_WRITE 0x20 /* W: write, R: write in progress */
+#define ICE1712_AC97_READ 0x10 /* W: read, R: read in progress */
+#define ICE1712_AC97_READY 0x08 /* codec ready status bit */
+#define ICE1712_AC97_PBK_VSR 0x02 /* playback VSR */
+#define ICE1712_AC97_CAP_VSR 0x01 /* capture VSR */
#define ICE1712_REG_AC97_DATA 0x0a /* word (little endian) */
#define ICE1712_REG_MPU1_CTRL 0x0c /* byte */
#define ICE1712_REG_MPU1_DATA 0x0d /* byte */
#define ICE1712_REG_I2C_DEV_ADDR 0x10 /* byte */
-#define ICE1712_I2C_WRITE 0x01 /* write direction */
+#define ICE1712_I2C_WRITE 0x01 /* write direction */
#define ICE1712_REG_I2C_BYTE_ADDR 0x11 /* byte */
#define ICE1712_REG_I2C_DATA 0x12 /* byte */
#define ICE1712_REG_I2C_CTRL 0x13 /* byte */
-#define ICE1712_I2C_EEPROM 0x80 /* EEPROM exists */
-#define ICE1712_I2C_BUSY 0x01 /* busy bit */
+#define ICE1712_I2C_EEPROM 0x80 /* EEPROM exists */
+#define ICE1712_I2C_BUSY 0x01 /* busy bit */
#define ICE1712_REG_CONCAP_ADDR 0x14 /* dword - consumer capture */
#define ICE1712_REG_CONCAP_COUNT 0x18 /* word - current/base count */
#define ICE1712_REG_SERR_SHADOW 0x1b /* byte */
@@ -128,14 +128,14 @@
#define ICE1712_DSC_ADDR1 0x02 /* dword - base address 1 */
#define ICE1712_DSC_COUNT1 0x03 /* word - count 1 */
#define ICE1712_DSC_CONTROL 0x04 /* byte - control & status */
-#define ICE1712_BUFFER1 0x80 /* buffer1 is active */
-#define ICE1712_BUFFER1_AUTO 0x40 /* buffer1 auto init */
-#define ICE1712_BUFFER0_AUTO 0x20 /* buffer0 auto init */
-#define ICE1712_FLUSH 0x10 /* flush FIFO */
-#define ICE1712_STEREO 0x08 /* stereo */
-#define ICE1712_16BIT 0x04 /* 16-bit data */
-#define ICE1712_PAUSE 0x02 /* pause */
-#define ICE1712_START 0x01 /* start */
+#define ICE1712_BUFFER1 0x80 /* buffer1 is active */
+#define ICE1712_BUFFER1_AUTO 0x40 /* buffer1 auto init */
+#define ICE1712_BUFFER0_AUTO 0x20 /* buffer0 auto init */
+#define ICE1712_FLUSH 0x10 /* flush FIFO */
+#define ICE1712_STEREO 0x08 /* stereo */
+#define ICE1712_16BIT 0x04 /* 16-bit data */
+#define ICE1712_PAUSE 0x02 /* pause */
+#define ICE1712_START 0x01 /* start */
#define ICE1712_DSC_RATE 0x05 /* dword - rate */
#define ICE1712_DSC_VOLUME 0x06 /* word - volume control */
@@ -146,12 +146,12 @@
#define ICEMT(ice, x) ((ice)->profi_port + ICE1712_MT_##x)
#define ICE1712_MT_IRQ 0x00 /* byte - interrupt mask */
-#define ICE1712_MULTI_CAPTURE 0x80 /* capture IRQ */
-#define ICE1712_MULTI_PLAYBACK 0x40 /* playback IRQ */
-#define ICE1712_MULTI_CAPSTATUS 0x02 /* capture IRQ status */
-#define ICE1712_MULTI_PBKSTATUS 0x01 /* playback IRQ status */
+#define ICE1712_MULTI_CAPTURE 0x80 /* capture IRQ */
+#define ICE1712_MULTI_PLAYBACK 0x40 /* playback IRQ */
+#define ICE1712_MULTI_CAPSTATUS 0x02 /* capture IRQ status */
+#define ICE1712_MULTI_PBKSTATUS 0x01 /* playback IRQ status */
#define ICE1712_MT_RATE 0x01 /* byte - sampling rate select */
-#define ICE1712_SPDIF_MASTER 0x10 /* S/PDIF input is master clock */
+#define ICE1712_SPDIF_MASTER 0x10 /* S/PDIF input is master clock */
#define ICE1712_MT_I2S_FORMAT 0x02 /* byte - I2S data format */
#define ICE1712_MT_AC97_INDEX 0x04 /* byte - AC'97 index */
#define ICE1712_MT_AC97_CMD 0x05 /* byte - AC'97 command & status */
@@ -161,14 +161,14 @@
#define ICE1712_MT_PLAYBACK_SIZE 0x14 /* word - playback size */
#define ICE1712_MT_PLAYBACK_COUNT 0x16 /* word - playback count */
#define ICE1712_MT_PLAYBACK_CONTROL 0x18 /* byte - control */
-#define ICE1712_CAPTURE_START_SHADOW 0x04 /* capture start */
-#define ICE1712_PLAYBACK_PAUSE 0x02 /* playback pause */
-#define ICE1712_PLAYBACK_START 0x01 /* playback start */
+#define ICE1712_CAPTURE_START_SHADOW 0x04 /* capture start */
+#define ICE1712_PLAYBACK_PAUSE 0x02 /* playback pause */
+#define ICE1712_PLAYBACK_START 0x01 /* playback start */
#define ICE1712_MT_CAPTURE_ADDR 0x20 /* dword - capture address */
#define ICE1712_MT_CAPTURE_SIZE 0x24 /* word - capture size */
#define ICE1712_MT_CAPTURE_COUNT 0x26 /* word - capture count */
#define ICE1712_MT_CAPTURE_CONTROL 0x28 /* byte - control */
-#define ICE1712_CAPTURE_START 0x01 /* capture start */
+#define ICE1712_CAPTURE_START 0x01 /* capture start */
#define ICE1712_MT_ROUTE_PSDOUT03 0x30 /* word */
#define ICE1712_MT_ROUTE_SPDOUT 0x32 /* word */
#define ICE1712_MT_ROUTE_CAPTURE 0x34 /* dword */
@@ -176,7 +176,7 @@
#define ICE1712_MT_MONITOR_INDEX 0x3a /* byte */
#define ICE1712_MT_MONITOR_RATE 0x3b /* byte */
#define ICE1712_MT_MONITOR_ROUTECTRL 0x3c /* byte */
-#define ICE1712_ROUTE_AC97 0x01 /* route digital mixer output to AC'97 */
+#define ICE1712_ROUTE_AC97 0x01 /* route digital mixer output to AC'97 */
#define ICE1712_MT_MONITOR_PEAKINDEX 0x3e /* byte */
#define ICE1712_MT_MONITOR_PEAKDATA 0x3f /* byte */
@@ -186,9 +186,9 @@
/* PCI[60] System Configuration */
#define ICE1712_CFG_CLOCK 0xc0
-#define ICE1712_CFG_CLOCK512 0x00 /* 22.5692Mhz, 44.1kHz*512 */
-#define ICE1712_CFG_CLOCK384 0x40 /* 16.9344Mhz, 44.1kHz*384 */
-#define ICE1712_CFG_EXT 0x80 /* external clock */
+#define ICE1712_CFG_CLOCK512 0x00 /* 22.5692Mhz, 44.1kHz*512 */
+#define ICE1712_CFG_CLOCK384 0x40 /* 16.9344Mhz, 44.1kHz*384 */
+#define ICE1712_CFG_EXT 0x80 /* external clock */
#define ICE1712_CFG_2xMPU401 0x20 /* two MPU401 UARTs */
#define ICE1712_CFG_NO_CON_AC97 0x10 /* consumer AC'97 codec is not present */
#define ICE1712_CFG_ADC_MASK 0x0c /* one, two, three, four stereo ADCs */
--
1.9.1
1
0
This patch adds support for the wm8973 codec, based on the
existing wm8971 codec driver.
Any comments about improving the patch are welcome.
Thanks.
Signed-off-by: Xavier Hsu <xavier.hsu(a)linaro.org>
---
Documentation/devicetree/bindings/sound/wm8973.txt | 26 +
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/wm8973.c | 1028 ++++++++++++++++++++
sound/soc/codecs/wm8973.h | 57 ++
5 files changed, 1117 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/wm8973.txt
create mode 100644 sound/soc/codecs/wm8973.c
create mode 100644 sound/soc/codecs/wm8973.h
diff --git a/Documentation/devicetree/bindings/sound/wm8973.txt b/Documentation/devicetree/bindings/sound/wm8973.txt
new file mode 100644
index 0000000..2374873
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wm8973.txt
@@ -0,0 +1,26 @@
+WM8973 audio CODEC
+
+These devices support both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+
+ - compatible : "wlf,wm8973".
+
+ - reg : the I2C address of the device for I2C, the chip select
+ number for SPI.
+
+Optional properties:
+
+ - mclk-div : Setting the CLKDIV2 bit for dividing MCLK.
+ mclk-div = <0> (Default & not divide).
+ mclk-div = <1> (Divide by 2).
+
+Example:
+
+codec: wm8973@1a {
+ compatible = "wlf,wm8973";
+ reg = <0x1a>;
+
+ mclk-div = <1>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 350878e..acf83bd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -139,6 +139,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8961 if I2C
select SND_SOC_WM8962 if I2C && INPUT
select SND_SOC_WM8971 if I2C
+ select SND_SOC_WM8973 if I2C
select SND_SOC_WM8974 if I2C
select SND_SOC_WM8978 if I2C
select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI
@@ -692,6 +693,9 @@ config SND_SOC_WM8962
config SND_SOC_WM8971
tristate
+config SND_SOC_WM8973
+ tristate
+
config SND_SOC_WM8974
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 1bd6e1c..aad29a3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -141,6 +141,7 @@ snd-soc-wm8960-objs := wm8960.o
snd-soc-wm8961-objs := wm8961.o
snd-soc-wm8962-objs := wm8962.o
snd-soc-wm8971-objs := wm8971.o
+snd-soc-wm8973-objs := wm8973.o
snd-soc-wm8974-objs := wm8974.o
snd-soc-wm8978-objs := wm8978.o
snd-soc-wm8983-objs := wm8983.o
@@ -303,6 +304,7 @@ obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
+obj-$(CONFIG_SND_SOC_WM8973) += snd-soc-wm8973.o
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
obj-$(CONFIG_SND_SOC_WM8983) += snd-soc-wm8983.o
diff --git a/sound/soc/codecs/wm8973.c b/sound/soc/codecs/wm8973.c
new file mode 100644
index 0000000..fc03de3
--- /dev/null
+++ b/sound/soc/codecs/wm8973.c
@@ -0,0 +1,1028 @@
+/*
+ * wm8973.c -- WM8973 ALSA SoC Audio driver
+ *
+ * Copyright (C) 2013 -2014 Fujitsu Semiconductor, Ltd
+ * Copyright (C) 2014 Linaro, Ltd Xavier Hsu <xavier.hsu(a)linaro.org>
+ *
+ * Based on wm8971 driver Copyright 2005 Lab126, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8973.h"
+
+static int mclk_div;
+
+struct wm8973_priv {
+ struct regmap *regmap;
+ unsigned int sysclk;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ int playback_fs;
+ bool deemph;
+};
+
+/*
+ * wm8973 register cache
+ * We can't read the WM8973 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8973_reg_defaults[] = {
+ { 0, 0x0097 },
+ { 1, 0x0097 },
+ { 2, 0x0079 },
+ { 3, 0x0079 },
+ { 4, 0x0000 },
+ { 5, 0x0008 },
+ { 6, 0x0000 },
+ { 7, 0x000a },
+ { 8, 0x0000 },
+ { 9, 0x0000 },
+ { 10, 0x00ff },
+ { 11, 0x00ff },
+ { 12, 0x000f },
+ { 13, 0x000f },
+ { 14, 0x0000 },
+ { 15, 0x0000 },
+ { 16, 0x0000 },
+ { 17, 0x007b },
+ { 18, 0x0000 },
+ { 19, 0x0032 },
+ { 20, 0x0000 },
+ { 21, 0x01c3 },
+ { 22, 0x01c3 },
+ { 23, 0x0040 },
+ { 24, 0x0014 },
+ { 25, 0x01c2 },
+ { 26, 0x0060 },
+ { 27, 0x0000 },
+ { 28, 0x0000 },
+ { 29, 0x0000 },
+ { 30, 0x0000 },
+ { 31, 0x0000 },
+ { 32, 0x0000 },
+ { 33, 0x0000 },
+ { 34, 0x0050 },
+ { 35, 0x0050 },
+ { 36, 0x0050 },
+ { 37, 0x0050 },
+ { 38, 0x0050 },
+ { 39, 0x0050 },
+ { 40, 0x0079 },
+ { 41, 0x0079 },
+ { 42, 0x0079 },
+};
+
+static const char const *wm8973_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char const *wm8973_bass_filter[] = { "130Hz @ 48kHz",
+ "200Hz @ 48kHz" };
+static const char const *wm8973_treble[] = {"8kHz", "4kHz"};
+static const char const *wm8973_3d_lc[] = {"200Hz", "500Hz"};
+static const char const *wm8973_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char const *wm8973_3d_func[] = {"Capture", "Playback"};
+static const char const *wm8973_alc_func[] = {"Off", "Right", "Left",
+ "Stereo"};
+static const char const *wm8973_ng_type[] = {"Constant PGA Gain",
+ "Mute ADC Output"};
+static const char const *wm8973_line_mux[] = {"Line 1", "Line 2", "Line 3",
+ "PGA", "Differential"};
+static const char const *wm8973_pga_sel[] = {"Line 1", "Line 2", "Line 3",
+ "Differential"};
+static const char const *wm8973_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
+ "ROUT1"};
+static const char const *wm8973_diff_sel[] = {"Line 1", "Line 2"};
+static const char const *wm8973_adcpol[] = {"Normal", "L Invert", "R Invert",
+ "L + R Invert"};
+static const char const *wm8973_mono_mux[] = {"Stereo", "Mono (Left)",
+ "Mono (Right)", "Digital Mono"};
+
+static const SOC_ENUM_SINGLE_DECL(bass_boost, WM8973_BASS, 7, wm8973_bass);
+static const SOC_ENUM_SINGLE_DECL(bass_filter, WM8973_BASS,
+ 6, wm8973_bass_filter);
+static const SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8973_TREBLE,
+ 6, wm8973_treble);
+static const SOC_ENUM_SINGLE_DECL(lower_cutoff, WM8973_3D, 5, wm8973_3d_lc);
+static const SOC_ENUM_SINGLE_DECL(upper_cutoff, WM8973_3D, 6, wm8973_3d_uc);
+static const SOC_ENUM_SINGLE_DECL(mode, WM8973_3D, 7, wm8973_3d_func);
+static const SOC_ENUM_SINGLE_DECL(alc_capture_func, WM8973_ALC1,
+ 7, wm8973_alc_func);
+static const SOC_ENUM_SINGLE_DECL(alc_capture_ngtype, WM8973_NGATE,
+ 1, wm8973_ng_type);
+static const SOC_ENUM_SINGLE_DECL(left_line, WM8973_LOUTM1,
+ 0, wm8973_line_mux);
+static const SOC_ENUM_SINGLE_DECL(right_line, WM8973_ROUTM1,
+ 0, wm8973_line_mux);
+static const SOC_ENUM_SINGLE_DECL(left_pga, WM8973_LADCIN, 6, wm8973_pga_sel);
+static const SOC_ENUM_SINGLE_DECL(right_pga, WM8973_RADCIN, 6, wm8973_pga_sel);
+static const SOC_ENUM_SINGLE_DECL(out3, WM8973_ADCTL2, 7, wm8973_out3);
+static const SOC_ENUM_SINGLE_DECL(diffmux, WM8973_ADCIN, 8, wm8973_diff_sel);
+static const SOC_ENUM_SINGLE_DECL(capture_polarity, WM8973_ADCDAC,
+ 5, wm8973_adcpol);
+static const SOC_ENUM_SINGLE_DECL(monomux, WM8973_ADCIN, 6, wm8973_mono_mux);
+
+static int wm8973_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int wm8973_set_deemph(struct snd_soc_codec *codec)
+{
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+ int val = 0, i, best = 0;
+
+ /* If we're using deemphasis select the nearest available sample
+ * rate.
+ */
+ if (wm8973->deemph) {
+ best = 1;
+ for (i = 2; i < ARRAY_SIZE(wm8973_deemph); i++) {
+ if (abs(wm8973_deemph[i] - wm8973->playback_fs) <
+ abs(wm8973_deemph[best] - wm8973->playback_fs))
+ best = i;
+ }
+ val = best << 1;
+ }
+
+ dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
+ best, wm8973_deemph[best]);
+
+ return snd_soc_update_bits(codec, WM8973_ADCDAC, 0x6, val);
+}
+
+static int wm8973_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.enumerated.item[0] = wm8973->deemph;
+
+ return 0;
+}
+
+static int wm8973_put_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+ int deemph = ucontrol->value.enumerated.item[0];
+ int ret = 0;
+
+ if (deemph > 1)
+ return -EINVAL;
+
+ mutex_lock(&codec->mutex);
+ if (wm8973->deemph != deemph) {
+ wm8973->deemph = deemph;
+ wm8973_set_deemph(codec);
+
+ ret = 1;
+ }
+ mutex_unlock(&codec->mutex);
+
+ return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol, -6700, 91, 0);
+static const DECLARE_TLV_DB_SCALE(attenuate_6db, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol, -12700, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_vol, -600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_vol, -2850, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_vol, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol, -9700, 50, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_out_vol, -1500, 300, 0);
+
+static const struct snd_kcontrol_new wm8973_snd_controls[] = {
+ /* Left & Right Input volume */
+ SOC_DOUBLE_R_TLV("Capture Volume", WM8973_LINVOL, WM8973_RINVOL,
+ 0, 63, 0, in_vol),
+ SOC_DOUBLE_R("Capture ZC Switch", WM8973_LINVOL, WM8973_RINVOL,
+ 6, 1, 0),
+ SOC_DOUBLE_R("Capture Switch", WM8973_LINVOL, WM8973_RINVOL, 7, 1, 1),
+
+ /* LOUT1 & ROUT1 volume */
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8973_LOUT1V,
+ WM8973_ROUT1V, 0, 127, 0, out_vol),
+ SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8973_LOUT1V,
+ WM8973_ROUT1V, 7, 1, 0),
+
+ /* ADC & DAC control */
+ SOC_SINGLE("Capture Filter Switch", WM8973_ADCDAC, 0, 1, 1),
+ SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0,
+ wm8973_get_deemph, wm8973_put_deemph),
+ SOC_ENUM("Capture Polarity", capture_polarity),
+ SOC_SINGLE_TLV("Playback 6dB Attenuate", WM8973_ADCDAC,
+ 7, 1, 0, attenuate_6db),
+ SOC_SINGLE_TLV("Capture 6dB Attenuate", WM8973_ADCDAC,
+ 8, 1, 0, attenuate_6db),
+ /* ADCDAC Bit 4 - HPOR */
+
+ /* Left & Right Channel Digital Volume */
+ SOC_DOUBLE_R_TLV("DAC Volume", WM8973_LDAC, WM8973_RDAC,
+ 0, 255, 0, dac_vol),
+
+ /* Bass Control */
+ SOC_SINGLE_TLV("Bass Volume", WM8973_BASS, 0, 15, 1, tone_vol),
+ SOC_ENUM("Bass Boost", bass_boost),
+ SOC_ENUM("Bass Filter", bass_filter),
+
+ /* Treble Control */
+ SOC_SINGLE_TLV("Treble Volume", WM8973_TREBLE, 0, 15, 0, tone_vol),
+ SOC_ENUM("Treble Cut-off", treble_cutoff),
+
+ /* 3D Control */
+ SOC_SINGLE("3D Switch", WM8973_3D, 0, 1, 0),
+ SOC_SINGLE("3D Volume", WM8973_3D, 1, 15, 0),
+ SOC_ENUM("3D Lower Cut-off", lower_cutoff),
+ SOC_ENUM("3D Upper Cut-off", upper_cutoff),
+ SOC_ENUM("3D Mode", mode),
+
+ /* ALC1 & ALC2 & ALC3 Control */
+ SOC_SINGLE_TLV("ALC Capture Target Volume", WM8973_ALC1,
+ 0, 15, 0, alc_tar_vol),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", WM8973_ALC1,
+ 4, 7, 0, alc_max_vol),
+ SOC_ENUM("ALC Capture Function", alc_capture_func),
+
+ SOC_SINGLE("ALC Capture Hold Time", WM8973_ALC2, 0, 15, 0),
+ SOC_SINGLE("ALC Capture ZC Switch", WM8973_ALC2, 7, 1, 0),
+
+ SOC_SINGLE("ALC Capture Attack Time", WM8973_ALC3, 0, 15, 0),
+ SOC_SINGLE("ALC Capture Decay Time", WM8973_ALC3, 4, 15, 0),
+
+ /* Noise Gate Control */
+ SOC_SINGLE("ALC Capture NG Switch", WM8973_NGATE, 0, 1, 0),
+ SOC_ENUM("ALC Capture NG Type", alc_capture_ngtype),
+ SOC_SINGLE("ALC Capture NG Threshold", WM8973_NGATE, 3, 31, 0),
+
+ /* Left & Right ADC Digital Volume*/
+ SOC_DOUBLE_R_TLV("ADC Volume", WM8973_LADC, WM8973_RADC,
+ 0, 255, 0, adc_vol),
+
+ /* Additional Control 1 */
+ SOC_SINGLE("ZC Timeout Switch", WM8973_ADCTL1, 0, 1, 0),
+ SOC_SINGLE("Playback Invert Switch", WM8973_ADCTL1, 1, 1, 0),
+ SOC_SINGLE("Analogue Bias", WM8973_ADCTL1, 6, 3, 0),
+ /* ADCTL1 Bit 2,3 - DATSEL */
+ /* ADCTL1 Bit 6,7 - VSEL */
+
+ /* Additional Control 2 */
+ SOC_SINGLE("Right Speaker Playback Invert Switch", WM8973_ADCTL2,
+ 4, 1, 0),
+ /* ADCTL2 Bit 2 - LRCM */
+ SOC_SINGLE("LRCLK Switch", WM8973_ADCTL2, 2, 1, 0),
+ /* ADCTL2 Bit 3 - TRI */
+ SOC_SINGLE("Headphone Switch POL", WM8973_ADCTL2, 5, 1, 0),
+ SOC_SINGLE("Headphone Switch EN", WM8973_ADCTL2, 6, 1, 0),
+
+ /* Additional Control 3 */
+ /* ADCTL3 Bit 5 - HPFLREN */
+ /* ADCTL3 Bit 6 - VROI */
+ /* ADCTL3 Bit 7,8 - ADCLRM */
+
+ /* ADC input Mode */
+ /* ADCIN Bit 4 - LDCM */
+ /* ADCIN Bit 5 - RDCM */
+ /* ADCIN Bit 6,7 - MONOMIX */
+
+ /* Left & Right ADC Signal Path Control*/
+ SOC_DOUBLE_R("Mic Boost", WM8973_LADCIN, WM8973_RADCIN, 4, 3, 0),
+
+ /* Left OUT Mixer Control */
+ SOC_DOUBLE_R_TLV("Bypass Left Playback Volume", WM8973_LOUTM1,
+ WM8973_LOUTM2, 4, 7, 1, bypass_out_vol),
+
+ /* Right OUT Mixer Control */
+ SOC_DOUBLE_R_TLV("Bypass Right Playback Volume", WM8973_ROUTM1,
+ WM8973_ROUTM2, 4, 7, 1, bypass_out_vol),
+
+ /* Mono OUT Mixer Control */
+ SOC_DOUBLE_R_TLV("Bypass Mono Playback Volume", WM8973_MOUTM1,
+ WM8973_MOUTM2, 4, 7, 1, bypass_out_vol),
+
+ /* LOUT2 & ROUT2 volume */
+ SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8973_LOUT2V,
+ WM8973_ROUT2V, 0, 127, 0, out_vol),
+ SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8973_LOUT2V,
+ WM8973_ROUT2V, 7, 1, 0),
+
+ /* MONOOUT volume */
+ SOC_SINGLE_TLV("Mono Playback Volume", WM8973_MOUTV,
+ 0, 127, 0, out_vol),
+ SOC_SINGLE("Mono Playback ZC Switch", WM8973_MOUTV, 7, 1, 0),
+
+ SOC_SINGLE("Right Out 2", WM8973_PWR2, 3, 1, 0),
+ SOC_SINGLE("Left Out 2", WM8973_PWR2, 4, 1, 0),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8973_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8973_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8973_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8973_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8973_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8973_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8973_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8973_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8973_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8973_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8973_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8973_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8973_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8973_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8973_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8973_left_line_controls =
+SOC_DAPM_ENUM("Route", left_line);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8973_right_line_controls =
+SOC_DAPM_ENUM("Route", right_line);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8973_left_pga_controls =
+SOC_DAPM_ENUM("Route", left_pga);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8973_right_pga_controls =
+SOC_DAPM_ENUM("Route", right_pga);
+
+/* Out 3 Mux */
+static const struct snd_kcontrol_new wm8973_out3_controls =
+SOC_DAPM_ENUM("Route", out3);
+
+/* Differential Mux */
+static const struct snd_kcontrol_new wm8973_diffmux_controls =
+SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8973_monomux_controls =
+SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget wm8973_dapm_widgets[] = {
+ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+ &wm8973_left_mixer_controls[0],
+ ARRAY_SIZE(wm8973_left_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+ &wm8973_right_mixer_controls[0],
+ ARRAY_SIZE(wm8973_right_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("Mono Mixer", WM8973_PWR2, 2, 0,
+ &wm8973_mono_mixer_controls[0],
+ ARRAY_SIZE(wm8973_mono_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("Right Out 2", WM8973_PWR2, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 2", WM8973_PWR2, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 1", WM8973_PWR2, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 1", WM8973_PWR2, 6, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8973_PWR2, 7, 0),
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8973_PWR2, 8, 0),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", WM8973_PWR1, 1, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8973_PWR1, 2, 0),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8973_PWR1, 3, 0),
+ SND_SOC_DAPM_MUX("Right PGA Mux", WM8973_PWR1, 4, 0,
+ &wm8973_right_pga_controls),
+ SND_SOC_DAPM_MUX("Left PGA Mux", WM8973_PWR1, 5, 0,
+ &wm8973_left_pga_controls),
+
+ SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_left_line_controls),
+ SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_right_line_controls),
+
+ SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_out3_controls),
+ SND_SOC_DAPM_PGA("Out 3", WM8973_PWR2, 1, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Mono Out 1", WM8973_PWR2, 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_diffmux_controls),
+
+ SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_monomux_controls),
+ SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+ &wm8973_monomux_controls),
+
+ SND_SOC_DAPM_OUTPUT("LOUT1"),
+ SND_SOC_DAPM_OUTPUT("ROUT1"),
+ SND_SOC_DAPM_OUTPUT("LOUT2"),
+ SND_SOC_DAPM_OUTPUT("ROUT2"),
+ SND_SOC_DAPM_OUTPUT("MONO1"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+ SND_SOC_DAPM_OUTPUT("VREF"),
+
+ SND_SOC_DAPM_INPUT("LINPUT1"),
+ SND_SOC_DAPM_INPUT("LINPUT2"),
+ SND_SOC_DAPM_INPUT("LINPUT3"),
+ SND_SOC_DAPM_INPUT("RINPUT1"),
+ SND_SOC_DAPM_INPUT("RINPUT2"),
+ SND_SOC_DAPM_INPUT("RINPUT3"),
+};
+
+static const struct snd_soc_dapm_route wm8973_dapm_routes[] = {
+ {"Left Mixer", "Playback Switch", "Left DAC"},
+ {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Left Mixer", "Right Playback Switch", "Right DAC"},
+ {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ {"Right Mixer", "Left Playback Switch", "Left DAC"},
+ {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Right Mixer", "Playback Switch", "Right DAC"},
+ {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ {"Left Out 1", NULL, "Left Mixer"},
+ {"LOUT1", NULL, "Left Out 1"},
+
+ {"Left Out 2", NULL, "Left Mixer"},
+ {"LOUT2", NULL, "Left Out 2"},
+
+ {"Right Out 1", NULL, "Right Mixer"},
+ {"ROUT1", NULL, "Right Out 1"},
+
+ {"Right Out 2", NULL, "Right Mixer"},
+ {"ROUT2", NULL, "Right Out 2"},
+
+ {"Mono Mixer", "Left Playback Switch", "Left DAC"},
+ {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+ {"Mono Mixer", "Right Playback Switch", "Right DAC"},
+ {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ {"Mono Out 1", NULL, "Mono Mixer"},
+ {"MONO1", NULL, "Mono Out 1"},
+
+ {"Out3 Mux", "VREF", "VREF"},
+ {"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
+ {"Out3 Mux", "ROUT1", "Right Mixer"},
+ {"Out3 Mux", "MonoOut", "MONO1"},
+ {"Out 3", NULL, "Out3 Mux"},
+ {"OUT3", NULL, "Out 3"},
+
+ {"Left Line Mux", "Line 1", "LINPUT1"},
+ {"Left Line Mux", "Line 2", "LINPUT2"},
+ {"Left Line Mux", "Line 3", "LINPUT3"},
+ {"Left Line Mux", "PGA", "Left PGA Mux"},
+ {"Left Line Mux", "Differential", "Differential Mux"},
+
+ {"Right Line Mux", "Line 1", "RINPUT1"},
+ {"Right Line Mux", "Line 2", "RINPUT2"},
+ {"Right Line Mux", "Line 3", "RINPUT3"},
+ /* {"Right Line Mux", "Mic", "MIC"}, */
+ {"Right Line Mux", "PGA", "Right PGA Mux"},
+ {"Right Line Mux", "Differential", "Differential Mux"},
+
+ {"Left PGA Mux", "Line 1", "LINPUT1"},
+ {"Left PGA Mux", "Line 2", "LINPUT2"},
+ {"Left PGA Mux", "Line 3", "LINPUT3"},
+ {"Left PGA Mux", "Differential", "Differential Mux"},
+
+ {"Right PGA Mux", "Line 1", "RINPUT1"},
+ {"Right PGA Mux", "Line 2", "RINPUT2"},
+ {"Right PGA Mux", "Line 3", "RINPUT3"},
+ {"Right PGA Mux", "Differential", "Differential Mux"},
+
+ {"Differential Mux", "Line 1", "LINPUT1"},
+ {"Differential Mux", "Line 1", "RINPUT1"},
+ {"Differential Mux", "Line 2", "LINPUT2"},
+ {"Differential Mux", "Line 2", "RINPUT2"},
+
+ {"Left ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+ {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+ {"Right ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+ {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+ {"Left ADC", NULL, "Left ADC Mux"},
+ {"Right ADC", NULL, "Right ADC Mux"},
+};
+
+struct _coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:5;
+ u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ /* 8k */
+ {12288000, 8000, 1536, 0x6, 0x0},
+ {11289600, 8000, 1408, 0x16, 0x0},
+ {18432000, 8000, 2304, 0x7, 0x0},
+ {16934400, 8000, 2112, 0x17, 0x0},
+ {12000000, 8000, 1500, 0x6, 0x1},
+
+ /* 11.025k */
+ {11289600, 11025, 1024, 0x18, 0x0},
+ {16934400, 11025, 1536, 0x19, 0x0},
+ {12000000, 11025, 1088, 0x19, 0x1},
+
+ /* 16k */
+ {12288000, 16000, 768, 0xa, 0x0},
+ {18432000, 16000, 1152, 0xb, 0x0},
+ {12000000, 16000, 750, 0xa, 0x1},
+
+ /* 22.05k */
+ {11289600, 22050, 512, 0x1a, 0x0},
+ {16934400, 22050, 768, 0x1b, 0x0},
+ {12000000, 22050, 544, 0x1b, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0xc, 0x0},
+ {18432000, 32000, 576, 0xd, 0x0},
+ {12000000, 32000, 375, 0xa, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x10, 0x0},
+ {16934400, 44100, 384, 0x11, 0x0},
+ {12000000, 44100, 272, 0x11, 0x1},
+
+ /* 48k */
+ {12288000, 48000, 256, 0x0, 0x0},
+ {18432000, 48000, 384, 0x1, 0x0},
+ {12000000, 48000, 250, 0x0, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0x1e, 0x0},
+ {16934400, 88200, 192, 0x1f, 0x0},
+ {12000000, 88200, 136, 0x1f, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0xe, 0x0},
+ {18432000, 96000, 192, 0xf, 0x0},
+ {12000000, 96000, 125, 0xe, 0x1},
+};
+
+static int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return -EINVAL;
+}
+
+/* The set of rates we can generate from the above for each SYSCLK */
+static unsigned int rates_12288[] = {
+ 8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+ .count = ARRAY_SIZE(rates_12288),
+ .list = rates_12288,
+};
+
+static unsigned int rates_112896[] = {
+ 8000, 11025, 22050, 44100, 88200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+ .count = ARRAY_SIZE(rates_112896),
+ .list = rates_112896,
+};
+
+static unsigned int rates_18432[] = {
+ 8000, 12000, 16000, 24000, 32000, 48000, 96000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_18432 = {
+ .count = ARRAY_SIZE(rates_18432),
+ .list = rates_18432,
+};
+
+static unsigned int rates_169344[] = {
+ 8000, 11025, 22050, 44100, 88200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_169344 = {
+ .count = ARRAY_SIZE(rates_169344),
+ .list = rates_169344,
+};
+
+static unsigned int rates_12[] = {
+ 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+ 48000, 88235, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12 = {
+ .count = ARRAY_SIZE(rates_12),
+ .list = rates_12,
+};
+
+static int wm8973_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+
+ switch (freq) {
+ case 12288000:
+ case 24576000:
+ wm8973->sysclk_constraints = &constraints_12288;
+ wm8973->sysclk = freq;
+ return 0;
+
+ case 11289600:
+ case 22579200:
+ wm8973->sysclk_constraints = &constraints_112896;
+ wm8973->sysclk = freq;
+ return 0;
+
+ case 18432000:
+ case 36864000:
+ wm8973->sysclk_constraints = &constraints_18432;
+ wm8973->sysclk = freq;
+ return 0;
+
+ case 16934400:
+ case 33868800:
+ wm8973->sysclk_constraints = &constraints_169344;
+ wm8973->sysclk = freq;
+ return 0;
+
+ case 12000000:
+ case 24000000:
+ wm8973->sysclk_constraints = &constraints_12;
+ wm8973->sysclk = freq;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int wm8973_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0040, 0x0040);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0002, 0x0002);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0001, 0x0001);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0003, 0x0003);
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0013, 0x0013);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0090, 0x0090);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0080, 0x0080);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ snd_soc_update_bits(codec, WM8973_IFACE, 0x0010, 0x0010);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8973_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+ u16 iface = snd_soc_read(codec, WM8973_IFACE) & 0x1f3;
+ u16 srate = snd_soc_read(codec, WM8973_SRATE) & 0x1c0;
+ int coeff = get_coeff(wm8973->sysclk, params_rate(params));
+
+ wm8973->playback_fs = params_rate(params);
+
+ /* bit size */
+ switch (params_width(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface |= 0x000c;
+ break;
+ }
+
+ wm8973_set_deemph(codec);
+
+ /* set iface & srate */
+ snd_soc_write(codec, WM8973_IFACE, iface);
+ if (coeff >= 0) {
+ snd_soc_write(codec, WM8973_SRATE, srate |
+ (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+ }
+
+ return 0;
+}
+
+static int wm8973_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 mute_reg = snd_soc_read(codec, WM8973_ADCDAC) & 0xfff7;
+
+ if (mute)
+ snd_soc_write(codec, WM8973_ADCDAC, mute_reg | 0x8);
+ else
+ snd_soc_write(codec, WM8973_ADCDAC, mute_reg);
+ return 0;
+}
+
+static int wm8973_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+ u16 pwr_reg = snd_soc_read(codec, WM8973_PWR1) & 0x03e;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ /* set vmid to 50k and unmute dac */
+ snd_soc_write(codec, WM8973_PWR1, pwr_reg | 0x00c2);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ regcache_sync(wm8973->regmap);
+
+ /* mute dac and set vmid to 500k, enable VREF */
+ snd_soc_write(codec, WM8973_PWR1, pwr_reg | 0x0141);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, WM8973_PWR1, 0x0001);
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+#define WM8973_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8973_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8973_dai_ops = {
+ .hw_params = wm8973_pcm_hw_params,
+ .digital_mute = wm8973_mute,
+ .set_fmt = wm8973_set_dai_fmt,
+ .set_sysclk = wm8973_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8973_dai[] = {
+ {
+ .name = "wm8973-hifi-playback",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8973_RATES,
+ .formats = WM8973_FORMATS,
+ },
+ .ops = &wm8973_dai_ops,
+ },
+ {
+ .name = "wm8973-hifi-capture",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8973_RATES,
+ .formats = WM8973_FORMATS,
+ },
+ .ops = &wm8973_dai_ops,
+ },
+};
+
+static int wm8973_suspend(struct snd_soc_codec *codec)
+{
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+
+ wm8973_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regcache_mark_dirty(wm8973->regmap);
+ return 0;
+}
+
+static int wm8973_resume(struct snd_soc_codec *codec)
+{
+ u16 reg;
+
+ wm8973_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* charge wm8973 caps */
+ if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
+ reg = snd_soc_read(codec, WM8973_PWR1) & 0xfe3e;
+ snd_soc_write(codec, WM8973_PWR1, reg | 0x01c0);
+ codec->dapm.bias_level = SND_SOC_BIAS_ON;
+ msleep(100);
+ }
+
+ return 0;
+}
+
+static int wm8973_probe(struct snd_soc_codec *codec)
+{
+ struct wm8973_priv *wm8973 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ u16 reg;
+ const int *p;
+
+ mclk_div = 0;
+
+ codec->control_data = wm8973->regmap;
+
+ snd_soc_write(codec, WM8973_RESET, 0);
+
+ if (codec->dev->of_node) {
+ p = of_get_property(codec->dev->of_node, "mclk-div", NULL);
+ if (p)
+ mclk_div = be32_to_cpu(*p);
+ }
+ /* Master Clock Divide by 2 (0 = not div, 1 = div by 2) */
+ if (mclk_div)
+ snd_soc_update_bits(codec, WM8973_SRATE, 0x0040, 0x0040);
+
+ /* charge output caps - set vmid to 5k for quick power up */
+ reg = snd_soc_read(codec, WM8973_PWR1) & 0x03e;
+ snd_soc_write(codec, WM8973_PWR1, reg | 0x1f0);
+
+ codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+
+ /* set the update bits */
+ snd_soc_update_bits(codec, WM8973_LDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_LOUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_ROUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_LOUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_ROUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_LINVOL, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8973_RINVOL, 0x0100, 0x0100);
+
+ return ret;
+}
+
+
+/* power down chip */
+static int wm8973_remove(struct snd_soc_codec *codec)
+{
+ wm8973_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+struct regmap *wm8973_get_regmap(struct device *dev)
+{
+ struct wm8973_priv *priv = dev_get_drvdata(dev);
+
+ return priv->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8973 = {
+ .probe = wm8973_probe,
+ .remove = wm8973_remove,
+ .suspend = wm8973_suspend,
+ .resume = wm8973_resume,
+ .set_bias_level = wm8973_set_bias_level,
+ .get_regmap = wm8973_get_regmap,
+ .controls = wm8973_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8973_snd_controls),
+ .dapm_widgets = wm8973_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8973_dapm_widgets),
+ .dapm_routes = wm8973_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8973_dapm_routes),
+};
+
+static const struct regmap_config wm8973_regmap = {
+ .reg_bits = 7,
+ .val_bits = 9,
+ .max_register = WM8973_MOUTV,
+ .reg_defaults = wm8973_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8973_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8973_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8973_priv *wm8973;
+ int ret;
+
+ wm8973 = devm_kzalloc(&i2c->dev, sizeof(struct wm8973_priv),
+ GFP_KERNEL);
+ if (wm8973 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8973);
+
+ wm8973->regmap = devm_regmap_init_i2c(i2c, &wm8973_regmap);
+ if (IS_ERR(wm8973->regmap)) {
+ ret = PTR_ERR(wm8973->regmap);
+ dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8973,
+ wm8973_dai, ARRAY_SIZE(wm8973_dai));
+
+ return ret;
+}
+
+static int wm8973_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id wm8973_i2c_id[] = {
+ { "wm8973", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8973_i2c_id);
+
+static const struct of_device_id wm8973_dt_ids[] = {
+ { .compatible = "wlf,wm8973" },
+ { /* sentinel */ }
+};
+
+static struct i2c_driver wm8973_i2c_driver = {
+ .driver = {
+ .name = "wm8973",
+ .owner = THIS_MODULE,
+ .of_match_table = wm8973_dt_ids,
+ },
+ .probe = wm8973_i2c_probe,
+ .remove = wm8973_i2c_remove,
+ .id_table = wm8973_i2c_id,
+};
+
+module_i2c_driver(wm8973_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8973 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("*wm8973*");
diff --git a/sound/soc/codecs/wm8973.h b/sound/soc/codecs/wm8973.h
new file mode 100644
index 0000000..5e6a026
--- /dev/null
+++ b/sound/soc/codecs/wm8973.h
@@ -0,0 +1,57 @@
+/*
+ * sound/soc/codecs/wm8973.h -- audio driver for WM8973
+ *
+ * Copyright (C) 2013 - 2014 Fujitsu Semiconductor, Ltd
+ *
+ * Author: Xavier Hsu <xavier.hsu(a)linaro.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _WM8973_H
+#define _WM8973_H
+
+#define WM8973_LINVOL 0x00
+#define WM8973_RINVOL 0x01
+#define WM8973_LOUT1V 0x02
+#define WM8973_ROUT1V 0x03
+#define WM8973_ADCDAC 0x05
+#define WM8973_IFACE 0x07
+#define WM8973_SRATE 0x08
+#define WM8973_LDAC 0x0a
+#define WM8973_RDAC 0x0b
+#define WM8973_BASS 0x0c
+#define WM8973_TREBLE 0x0d
+#define WM8973_RESET 0x0f
+#define WM8973_3D 0x10
+#define WM8973_ALC1 0x11
+#define WM8973_ALC2 0x12
+#define WM8973_ALC3 0x13
+#define WM8973_NGATE 0x14
+#define WM8973_LADC 0x15
+#define WM8973_RADC 0x16
+#define WM8973_ADCTL1 0x17
+#define WM8973_ADCTL2 0x18
+#define WM8973_PWR1 0x19
+#define WM8973_PWR2 0x1a
+#define WM8973_ADCTL3 0x1b
+#define WM8973_ADCIN 0x1f
+#define WM8973_LADCIN 0x20
+#define WM8973_RADCIN 0x21
+#define WM8973_LOUTM1 0x22
+#define WM8973_LOUTM2 0x23
+#define WM8973_ROUTM1 0x24
+#define WM8973_ROUTM2 0x25
+#define WM8973_MOUTM1 0x26
+#define WM8973_MOUTM2 0x27
+#define WM8973_LOUT2V 0x28
+#define WM8973_ROUT2V 0x29
+#define WM8973_MOUTV 0x2A
+
+#define WM8973_SYSCLK 0
+
+#endif
--
1.7.9.5
3
3
[alsa-devel] [PATCH 0/2] ASoC: add CSR SiRFSoC audio USP interface driver
by Rongjun Ying 01 Jul '14
by Rongjun Ying 01 Jul '14
01 Jul '14
This patchset adds the SiRF USP controller driver, this
driver uses the USP as I2S or DSP_A mode interface.
Rongjun Ying (2):
ASoC: sirf: Add audio usp interface driver
ASoC: sirf: Add device tree binding for the USP audio device
.../devicetree/bindings/sound/sirf-usp.txt | 27 ++
sound/soc/sirf/Kconfig | 6 +
sound/soc/sirf/Makefile | 2 +
sound/soc/sirf/sirf-usp.c | 409 +++++++++++++++++++++
sound/soc/sirf/sirf-usp.h | 293 +++++++++++++++
5 files changed, 737 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/sirf-usp.txt
create mode 100644 sound/soc/sirf/sirf-usp.c
create mode 100644 sound/soc/sirf/sirf-usp.h
--
1.9.3
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.
2
3
[alsa-devel] next-20140640 - fatal crash at boot time in sound drivers...
by Valdis Kletnieks 01 Jul '14
by Valdis Kletnieks 01 Jul '14
01 Jul '14
Seeing this on a Dell Latitude E6530 - kernel lives for just a few
seconds before committing hari-kiri trying to initialize the sound chipset.
lspci reports the following audio devices:
00:1b.0 Audio device: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller (rev 04)
01:00.1 Audio device: NVIDIA Corporation GF108 High Definition Audio Controller (rev a1)
Is working fine in next-20140618
This ring any bells, before I start doing a git bisect?
[ 2.467707] netconsole: network logging started
[ 2.467790] rtc_cmos 00:01: setting system clock to 2014-06-30 15:09:43 UTC (1404140983)
[ 2.468008] BUG: unable to handle kernel NULL pointer dereference at (null)
[ 2.468077] IP: [<ffffffff8128c97d>] __list_add+0x6e/0x13c
[ 2.468122] PGD 0
[ 2.468143] Oops: 0000 [#1] PREEMPT SMP
[ 2.468185] Modules linked in:
[ 2.468214] CPU: 2 PID: 84 Comm: kworker/2:2 Not tainted 3.16.0-rc3-next-20140630 #244
[ 2.468244] ALSA device list:
[ 2.468245] No soundcards found.
[ 2.468307] Hardware name: Dell Inc. Latitude E6530/07Y85M, BIOS A14 01/13/2014
[ 2.468311] Workqueue: events azx_probe_work
[ 2.468313] task: ffff8802237f12d0 ti: ffff8802237f4000 task.ti: ffff8802237f4000
[ 2.468316] RIP: 0010:[<ffffffff8128c97d>] [<ffffffff8128c97d>] __list_add+0x6e/0x13c
[ 2.468318] RSP: 0018:ffff8802237f7b60 EFLAGS: 00010206
[ 2.468319] RAX: ffff880223752dd0 RBX: 0000000000000000 RCX: 0000000000000000
[ 2.468320] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff81d2a3e0
[ 2.468322] RBP: ffff8802237f7b88 R08: ffff880223752d00 R09: 000000000000ffff
[ 2.468323] R10: ffff8802237f7ad8 R11: 00000000fffffffe R12: ffffffff81ea4e40
[ 2.468324] R13: ffff880223752d00 R14: 0000000000000000 R15: ffff88003f99fb00
[ 2.468326] FS: 0000000000000000(0000) GS:ffff88022dd00000(0000) knlGS:0000000000000000
[ 2.468327] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2.468328] CR2: 0000000000000000 CR3: 0000000001c10000 CR4: 00000000001407e0
[ 2.468329] Stack:
[ 2.468332] ffff88003f99f040 ffffffff81ea4e40 0000000000000000 ffffffff81b47254
[ 2.468336] ffff88003f99fb80 ffff8802237f7bb0 ffffffff814670a8 0000000000000000
[ 2.468339] ffff88003f8e9000 ffffffff818ba498 ffff8802237f7bc0 ffffffff8148c830
[ 2.468340] Call Trace:
[ 2.468345] [<ffffffff814670a8>] _snd_ctl_add_slave+0xb6/0xbf
[ 2.468349] [<ffffffff8148c830>] snd_ctl_add_slave+0xb/0xd
[ 2.468352] [<ffffffff8148c71d>] map_slaves+0xb4/0xec
[ 2.468354] [<ffffffff8148c825>] ? snd_hda_enum_helper_info+0x4b/0x4b
[ 2.468358] [<ffffffff8148d9a0>] __snd_hda_add_vmaster+0x9b/0xfc
[ 2.468361] [<ffffffff81499c9e>] snd_hda_gen_build_controls+0xff/0x1ab
[ 2.468365] [<ffffffff81491a63>] snd_hda_codec_build_controls+0x38/0x196
[ 2.468368] [<ffffffff81491bed>] snd_hda_build_controls+0x2c/0x87
[ 2.468370] [<ffffffff81496c4e>] azx_mixer_create+0x10/0x12
[ 2.468373] [<ffffffff814a2c06>] azx_probe_work+0x3db/0x519
[ 2.468378] [<ffffffff81057523>] process_one_work+0x296/0x4b8
[ 2.468381] [<ffffffff81057f2c>] worker_thread+0x3fc/0x54e
[ 2.468384] [<ffffffff81057b30>] ? cancel_delayed_work+0xb7/0xb7
[ 2.468387] [<ffffffff8105dbfc>] kthread+0xd6/0xde
[ 2.468390] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 2.468394] [<ffffffff8168bfac>] ret_from_fork+0x7c/0xb0
[ 2.468396] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 2.468443] Code: be 1d 00 00 00 48 c7 c2 f4 51 b0 81 48 c7 c7 41 52 b0 81 31 c0 e8 d3 0d db ff 31 d2 44 89 f6 48 c7 c7 e0 a3 d2 81 e8 62 ca e4 ff <4c> 39 23 48 c7 c7 b8 a3 d2 81 41 0f 95 c7 31 d2 45 0f b6 f7 44
[ 2.468445] RIP [<ffffffff8128c97d>] __list_add+0x6e/0x13c
[ 2.468446] RSP <ffff8802237f7b60>
[ 2.468447] CR2: 0000000000000000
[ 2.468449] ---[ end trace 2ff29d6bc6a184d4 ]---
[ 2.605416] tsc: Refined TSC clocksource calibration: 2691.263 MHz
[ 2.687337] usb 1-1: new high-speed USB device number 2 using ehci-pci
[ 2.741253] ata2: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
[ 2.742914] ata2.00: ATAPI: MATSHITA DVD+/-RW UJ8C2, 1.02, max UDMA/133
[ 2.744350] ata2.00: configured for UDMA/133
[ 2.745510] scsi 1:0:0:0: CD-ROM MATSHITA DVD+-RW UJ8C2 1.02 PQ: 0 ANSI: 5
[ 2.804514] usb 1-1: New USB device found, idVendor=8087, idProduct=0024
[ 2.804545] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2.804909] hub 1-1:1.0: USB hub found
[ 2.805005] hub 1-1:1.0: 6 ports detected
[ 2.908047] usb 2-1: new high-speed USB device number 2 using ehci-pci
[ 3.024199] usb 2-1: New USB device found, idVendor=8087, idProduct=0024
[ 3.024253] usb 2-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 3.024612] hub 2-1:1.0: USB hub found
[ 3.024694] hub 2-1:1.0: 8 ports detected
[ 3.179680] usb 3-1: new low-speed USB device number 2 using xhci_hcd
[ 3.358523] usb 3-1: New USB device found, idVendor=045e, idProduct=0023
[ 3.358578] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 3.358634] usb 3-1: Product: Microsoft Trackball Optical®
[ 3.358678] usb 3-1: Manufacturer: Microsoft
[ 3.358930] usb 3-1: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
[ 3.365460] input: Microsoft Microsoft Trackball Optical® as /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:045E:0023.0001/input/input9
[ 3.365884] hid-generic 0003:045E:0023.0001: input,hidraw0: USB HID v1.00 Mouse [Microsoft Microsoft Trackball Optical®] on usb-0000:00:14.0-1/input0
[ 3.518233] usb 3-4: new high-speed USB device number 3 using xhci_hcd
[ 4.742601] Switched to clocksource tsc
[ 4.742844] kworker/2:2 (84) used greatest stack depth: 11888 bytes left
[ 4.743118] BUG: unable to handle kernel paging request at ffffffffffffffa8
[ 4.746083] IP: [<ffffffff8105dfd2>] kthread_data+0xc/0x11
[ 4.749966] PGD 1c11067 PUD 1c13067 PMD 0
[ 4.754807] Oops: 0000 [#2] PREEMPT SMP
[ 4.759798] Modules linked in:
[ 4.764668] CPU: 2 PID: 84 Comm: kworker/2:2 Tainted: G D 3.16.0-rc3-next-20140630 #244
[ 4.769503] Hardware name: Dell Inc. Latitude E6530/07Y85M, BIOS A14 01/13/2014
[ 4.774468] task: ffff8802237f12d0 ti: ffff8802237f4000 task.ti: ffff8802237f4000
[ 4.779351] RIP: 0010:[<ffffffff8105dfd2>] [<ffffffff8105dfd2>] kthread_data+0xc/0x11
[ 4.784250] RSP: 0018:ffff8802237f77a0 EFLAGS: 00010002
[ 4.789373] RAX: 0000000000000000 RBX: ffff88022dd13d00 RCX: 000000000000000f
[ 4.794280] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff8802237f12d0
[ 4.799157] RBP: ffff8802237f77c8 R08: ffff88022dd13da8 R09: ffffffff81ea3000
[ 4.804085] R10: ffff8802237f7650 R11: ffff8802249ac780 R12: 0000000000000000
[ 4.808950] R13: 0000000000000002 R14: 0000000000000040 R15: ffff8802237f7898
[ 4.813761] FS: 0000000000000000(0000) GS:ffff88022dd00000(0000) knlGS:0000000000000000
[ 4.818642] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 4.823588] CR2: 0000000000000028 CR3: 0000000001c10000 CR4: 00000000001407e0
[ 4.828539] Stack:
[ 4.833335] ffffffff81058150 ffff88022dd13d00 0000000000000000 0000000000000002
[ 4.838307] 0000000000000040 ffff8802237f7838 ffffffff8168639f ffff8802237f7fd8
[ 4.843246] ffff8802237f12d0 ffff8802249ac780 0000000000013d00 ffff88022dd13d00
[ 4.848167] Call Trace:
[ 4.853149] [<ffffffff81058150>] ? wq_worker_sleeping+0x13/0x105
[ 4.858028] [<ffffffff8168639f>] __schedule+0x2a3/0xa91
[ 4.862946] [<ffffffff81686bf1>] schedule+0x64/0x66
[ 4.867860] [<ffffffff8103f119>] do_exit+0xbbf/0xc0c
[ 4.872616] [<ffffffff8107fc72>] ? arch_local_irq_save+0x9/0xc
[ 4.877432] [<ffffffff8100577f>] oops_end+0x7c/0x81
[ 4.882219] [<ffffffff8102f336>] no_context+0x25c/0x2b0
[ 4.887043] [<ffffffff8102f3f9>] __bad_area_nosemaphore+0x6f/0x1fe
[ 4.892019] [<ffffffff8102f596>] bad_area_nosemaphore+0xe/0x10
[ 4.897024] [<ffffffff8102f955>] __do_page_fault+0x3bd/0x724
[ 4.901834] [<ffffffff81081c77>] ? mark_lock+0x2a/0x203
[ 4.906643] [<ffffffff810829a6>] ? __lock_acquire+0x68c/0xed1
[ 4.911611] [<ffffffff810d89c4>] ? time_hardirqs_off+0x1b/0x2f
[ 4.916428] [<ffffffff8107ff5a>] ? trace_hardirqs_off_caller+0x4c/0xb9
[ 4.921245] [<ffffffff81282e0a>] ? trace_hardirqs_off_thunk+0x3a/0x3c
[ 4.926095] [<ffffffff8102fcc8>] do_page_fault+0xc/0xe
[ 4.930911] [<ffffffff8168dc52>] page_fault+0x22/0x30
[ 4.935712] [<ffffffff8128c97d>] ? __list_add+0x6e/0x13c
[ 4.940601] [<ffffffff814670a8>] _snd_ctl_add_slave+0xb6/0xbf
[ 4.945404] [<ffffffff8148c830>] snd_ctl_add_slave+0xb/0xd
[ 4.950219] [<ffffffff8148c71d>] map_slaves+0xb4/0xec
[ 4.954877] [<ffffffff8148c825>] ? snd_hda_enum_helper_info+0x4b/0x4b
[ 4.959733] [<ffffffff8148d9a0>] __snd_hda_add_vmaster+0x9b/0xfc
[ 4.964346] [<ffffffff81499c9e>] snd_hda_gen_build_controls+0xff/0x1ab
[ 4.968948] [<ffffffff81491a63>] snd_hda_codec_build_controls+0x38/0x196
[ 4.973562] [<ffffffff81491bed>] snd_hda_build_controls+0x2c/0x87
[ 4.978178] [<ffffffff81496c4e>] azx_mixer_create+0x10/0x12
[ 4.982693] [<ffffffff814a2c06>] azx_probe_work+0x3db/0x519
[ 4.987371] [<ffffffff81057523>] process_one_work+0x296/0x4b8
[ 4.991806] [<ffffffff81057f2c>] worker_thread+0x3fc/0x54e
[ 4.996432] [<ffffffff81057b30>] ? cancel_delayed_work+0xb7/0xb7
[ 5.000828] [<ffffffff8105dbfc>] kthread+0xd6/0xde
[ 5.005151] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 5.009500] [<ffffffff8168bfac>] ret_from_fork+0x7c/0xb0
[ 5.013921] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 5.018307] Code: 48 8b 04 25 80 b9 00 00 48 8b 80 d8 04 00 00 48 89 e5 5d 48 8b 40 98 48 c1 e8 02 83 e0 01 c3 48 8b 87 d8 04 00 00 55 48 89 e5 5d <48> 8b 40 a8 c3 55 ba 08 00 00 00 48 89 e5 50 48 8b b7 d8 04 00
[ 5.023570] RIP [<ffffffff8105dfd2>] kthread_data+0xc/0x11
[ 5.028173] RSP <ffff8802237f77a0>
[ 5.032760] CR2: ffffffffffffffa8
[ 5.037505] ---[ end trace 2ff29d6bc6a184d5 ]---
[ 5.211674] Fixing recursive fault but reboot is needed!
[ 5.216280] BUG: scheduling while atomic: kworker/2:2/84/0x00000004
[ 5.220852] INFO: lockdep is turned off.
[ 5.225435] Modules linked in:
[ 5.230060] irq event stamp: 4640
[ 5.234609] hardirqs last enabled at (4639): [<ffffffff8113286a>] __kmalloc+0x94/0x10d
[ 5.239246] hardirqs last disabled at (4640): [<ffffffff8168de43>] error_sti+0x5/0x6
[ 5.244073] softirqs last enabled at (4294): [<ffffffff81041faa>] __do_softirq+0x2ab/0x403
[ 5.248509] softirqs last disabled at (4255): [<ffffffff810423a5>] irq_exit+0x4c/0xbb
[ 5.253019] CPU: 2 PID: 84 Comm: kworker/2:2 Tainted: G D 3.16.0-rc3-next-20140630 #244
[ 5.257493] Hardware name: Dell Inc. Latitude E6530/07Y85M, BIOS A14 01/13/2014
[ 5.261861] 0000000000000000 ffff8802237f73f0 ffffffff81680ccb ffff8802237f12d0
[ 5.266268] 0000000000000001 ffff8802237f7408 ffffffff8106667f ffff88022dd13d00
[ 5.270961] ffff8802237f7478 ffffffff816861b6 ffff8802237f7fd8 ffff8802237f12d0
[ 5.275445] Call Trace:
[ 5.279729] [<ffffffff81680ccb>] dump_stack+0x51/0xaa
[ 5.284243] [<ffffffff8106667f>] __schedule_bug+0x5e/0x6d
[ 5.288769] [<ffffffff816861b6>] __schedule+0xba/0xa91
[ 5.293159] [<ffffffff81686bf1>] schedule+0x64/0x66
[ 5.297348] [<ffffffff8103e700>] do_exit+0x1a6/0xc0c
[ 5.301489] [<ffffffff8107fc72>] ? arch_local_irq_save+0x9/0xc
[ 5.305667] [<ffffffff81090e0b>] ? __rcu_read_unlock+0xf2/0xf9
[ 5.309791] [<ffffffff8108ab84>] ? kmsg_dump+0x18b/0x194
[ 5.313868] [<ffffffff8100577f>] oops_end+0x7c/0x81
[ 5.317922] [<ffffffff8102f336>] no_context+0x25c/0x2b0
[ 5.321983] [<ffffffff8102f3f9>] __bad_area_nosemaphore+0x6f/0x1fe
[ 5.326018] [<ffffffff8102f596>] bad_area_nosemaphore+0xe/0x10
[ 5.330032] [<ffffffff8102f955>] __do_page_fault+0x3bd/0x724
[ 5.334012] [<ffffffff81083554>] ? lock_acquire+0xc1/0x14e
[ 5.337966] [<ffffffff810d89c4>] ? time_hardirqs_off+0x1b/0x2f
[ 5.341895] [<ffffffff8168de43>] ? error_sti+0x5/0x6
[ 5.345767] [<ffffffff8107ff2d>] ? trace_hardirqs_off_caller+0x1f/0xb9
[ 5.349649] [<ffffffff81282e0a>] ? trace_hardirqs_off_thunk+0x3a/0x3c
[ 5.353528] [<ffffffff8102fcc8>] do_page_fault+0xc/0xe
[ 5.357389] [<ffffffff8168dc52>] page_fault+0x22/0x30
[ 5.361234] [<ffffffff8105dfd2>] ? kthread_data+0xc/0x11
[ 5.365089] [<ffffffff81058150>] ? wq_worker_sleeping+0x13/0x105
[ 5.368997] [<ffffffff8168639f>] __schedule+0x2a3/0xa91
[ 5.372809] [<ffffffff81686bf1>] schedule+0x64/0x66
[ 5.376729] [<ffffffff8103f119>] do_exit+0xbbf/0xc0c
[ 5.380532] [<ffffffff8107fc72>] ? arch_local_irq_save+0x9/0xc
[ 5.384415] [<ffffffff8100577f>] oops_end+0x7c/0x81
[ 5.388189] [<ffffffff8102f336>] no_context+0x25c/0x2b0
[ 5.392030] [<ffffffff8102f3f9>] __bad_area_nosemaphore+0x6f/0x1fe
[ 5.396037] [<ffffffff8102f596>] bad_area_nosemaphore+0xe/0x10
[ 5.400019] [<ffffffff8102f955>] __do_page_fault+0x3bd/0x724
[ 5.403823] [<ffffffff81081c77>] ? mark_lock+0x2a/0x203
[ 5.407624] [<ffffffff810829a6>] ? __lock_acquire+0x68c/0xed1
[ 5.411405] [<ffffffff810d89c4>] ? time_hardirqs_off+0x1b/0x2f
[ 5.415209] [<ffffffff8107ff5a>] ? trace_hardirqs_off_caller+0x4c/0xb9
[ 5.419107] [<ffffffff81282e0a>] ? trace_hardirqs_off_thunk+0x3a/0x3c
[ 5.422894] [<ffffffff8102fcc8>] do_page_fault+0xc/0xe
[ 5.426916] [<ffffffff8168dc52>] page_fault+0x22/0x30
[ 5.430708] [<ffffffff8128c97d>] ? __list_add+0x6e/0x13c
[ 5.434489] [<ffffffff814670a8>] _snd_ctl_add_slave+0xb6/0xbf
[ 5.438290] [<ffffffff8148c830>] snd_ctl_add_slave+0xb/0xd
[ 5.442229] [<ffffffff8148c71d>] map_slaves+0xb4/0xec
[ 5.446010] [<ffffffff8148c825>] ? snd_hda_enum_helper_info+0x4b/0x4b
[ 5.450140] [<ffffffff8148d9a0>] __snd_hda_add_vmaster+0x9b/0xfc
[ 5.453932] [<ffffffff81499c9e>] snd_hda_gen_build_controls+0xff/0x1ab
[ 5.457821] [<ffffffff81491a63>] snd_hda_codec_build_controls+0x38/0x196
[ 5.461724] [<ffffffff81491bed>] snd_hda_build_controls+0x2c/0x87
[ 5.465524] [<ffffffff81496c4e>] azx_mixer_create+0x10/0x12
[ 5.469319] [<ffffffff814a2c06>] azx_probe_work+0x3db/0x519
[ 5.473161] [<ffffffff81057523>] process_one_work+0x296/0x4b8
[ 5.476952] [<ffffffff81057f2c>] worker_thread+0x3fc/0x54e
[ 5.480734] [<ffffffff81057b30>] ? cancel_delayed_work+0xb7/0xb7
[ 5.484603] [<ffffffff8105dbfc>] kthread+0xd6/0xde
[ 5.488415] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 5.492334] [<ffffffff8168bfac>] ret_from_fork+0x7c/0xb0
[ 5.496116] [<ffffffff8105db26>] ? __kthread_parkme+0x62/0x62
[ 56.430656] Kernel panic - not syncing: Watchdog detected hard LOCKUP on cpu 2
[ 57.577582] Shutting down cpus with NMI
[ 57.580830] Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffff9fffffff)
3
2
'status' is not used in the function. Remove it.
Signed-off-by: Sachin Kamat <sachin.kamat(a)samsung.com>
Cc: Stephen Warren <swarren(a)wwwdotorg.org>
Cc: Thierry Reding <thierry.reding(a)gmail.com>
---
All patches in this series only compile tested.
---
sound/pci/hda/hda_tegra.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index a366ba9293a8..8cd7b06eecef 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -272,13 +272,9 @@ static int hda_tegra_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
- int status;
hda_tegra_enable_clocks(hda);
- /* Read STATESTS before controller reset */
- status = azx_readw(chip, STATESTS);
-
hda_tegra_init(hda);
azx_init_chip(chip, 1);
--
1.7.9.5
4
16
Re: [alsa-devel] [PATCH 2/2] ASoC: add driver for Rockchip RK3xxx I2S controller
by Lars-Peter Clausen 01 Jul '14
by Lars-Peter Clausen 01 Jul '14
01 Jul '14
On 07/01/2014 04:49 PM, Huang Tao wrote:
> Dear Lars:
>
> 于 2014年07月01日 17:51, Lars-Peter Clausen 写道:
>>> + /* Try to set the I2S Channel id from dt */
>>> >+ pdev->id = of_alias_get_id(np, "i2s");
>>> >+ dev_set_name(&pdev->dev, "%s.%d",
>>> >+ pdev->dev.driver->name,
>>> >+ pdev->id);
>> A device should not change its id or name.
>>
> Could you tell me the reason?
>
When registering a device the Linux device core that the id and name are
unique. If you change them behind the back of the core there is no guarantee
that they are still unique and undefined behavior might occur. Also changing
them can cause all kind of other weird behavior, e.g. the name no longer
matches the name of the sysfs files, etc.
- Lars
2
1