summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/arm/aaci.c1
-rw-r--r--sound/core/pcm.c5
-rw-r--r--sound/drivers/dummy.c4
-rw-r--r--sound/drivers/opl3/opl3_midi.c28
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c65
-rw-r--r--sound/drivers/pcsp/pcsp_mixer.c2
-rw-r--r--sound/parisc/harmony.c6
-rw-r--r--sound/pci/Kconfig1
-rw-r--r--sound/pci/ali5451/ali5451.c2
-rw-r--r--sound/pci/bt87x.c2
-rw-r--r--sound/pci/hda/hda_intel.c1
-rw-r--r--sound/pci/hda/patch_nvhdmi.c31
-rw-r--r--sound/pci/hda/patch_realtek.c98
-rw-r--r--sound/pci/hda/patch_sigmatel.c29
-rw-r--r--sound/pci/ice1712/amp.c8
-rw-r--r--sound/pci/ice1712/ice1712.c2
-rw-r--r--sound/pci/ice1712/ice1724.c8
-rw-r--r--sound/pci/via82xx.c86
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c21
-rw-r--r--sound/pcmcia/vx/vxpocket.c21
-rw-r--r--sound/ppc/Kconfig2
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/au1x/dbdma2.c117
-rw-r--r--sound/soc/au1x/psc-ac97.c194
-rw-r--r--sound/soc/au1x/psc-i2s.c189
-rw-r--r--sound/soc/au1x/psc.h7
-rw-r--r--sound/soc/codecs/Kconfig8
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ac97.c3
-rw-r--r--sound/soc/codecs/ad1836.c12
-rw-r--r--sound/soc/codecs/ad1938.c12
-rw-r--r--sound/soc/codecs/ad1980.c5
-rw-r--r--sound/soc/codecs/ad73311.c8
-rw-r--r--sound/soc/codecs/ads117x.c123
-rw-r--r--sound/soc/codecs/ads117x.h13
-rw-r--r--sound/soc/codecs/ak4104.c8
-rw-r--r--sound/soc/codecs/ak4535.c9
-rw-r--r--sound/soc/codecs/ak4642.c9
-rw-r--r--sound/soc/codecs/ak4671.c10
-rw-r--r--sound/soc/codecs/cs4270.c8
-rw-r--r--sound/soc/codecs/cx20442.c12
-rw-r--r--sound/soc/codecs/pcm3008.c9
-rw-r--r--sound/soc/codecs/ssm2602.c9
-rw-r--r--sound/soc/codecs/stac9766.c3
-rw-r--r--sound/soc/codecs/tlv320aic23.c11
-rw-r--r--sound/soc/codecs/tlv320aic26.c11
-rw-r--r--sound/soc/codecs/tlv320aic3x.c11
-rw-r--r--sound/soc/codecs/tlv320dac33.c11
-rw-r--r--sound/soc/codecs/twl4030.c275
-rw-r--r--sound/soc/codecs/uda134x.c9
-rw-r--r--sound/soc/codecs/uda1380.c9
-rw-r--r--sound/soc/codecs/wm8350.c13
-rw-r--r--sound/soc/codecs/wm8400.c12
-rw-r--r--sound/soc/codecs/wm8510.c10
-rw-r--r--sound/soc/codecs/wm8523.c9
-rw-r--r--sound/soc/codecs/wm8580.c9
-rw-r--r--sound/soc/codecs/wm8711.c9
-rw-r--r--sound/soc/codecs/wm8727.c135
-rw-r--r--sound/soc/codecs/wm8727.h21
-rw-r--r--sound/soc/codecs/wm8728.c10
-rw-r--r--sound/soc/codecs/wm8731.c60
-rw-r--r--sound/soc/codecs/wm8750.c9
-rw-r--r--sound/soc/codecs/wm8753.c10
-rw-r--r--sound/soc/codecs/wm8776.c9
-rw-r--r--sound/soc/codecs/wm8900.c13
-rw-r--r--sound/soc/codecs/wm8903.c11
-rw-r--r--sound/soc/codecs/wm8940.c7
-rw-r--r--sound/soc/codecs/wm8960.c9
-rw-r--r--sound/soc/codecs/wm8961.c10
-rw-r--r--sound/soc/codecs/wm8971.c11
-rw-r--r--sound/soc/codecs/wm8974.c9
-rw-r--r--sound/soc/codecs/wm8988.c10
-rw-r--r--sound/soc/codecs/wm8990.c10
-rw-r--r--sound/soc/codecs/wm8993.c11
-rw-r--r--sound/soc/codecs/wm9081.c10
-rw-r--r--sound/soc/codecs/wm9705.c9
-rw-r--r--sound/soc/codecs/wm9712.c9
-rw-r--r--sound/soc/codecs/wm9713.c8
-rw-r--r--sound/soc/davinci/davinci-i2s.c85
-rw-r--r--sound/soc/davinci/davinci-mcasp.c1
-rw-r--r--sound/soc/davinci/davinci-mcasp.h5
-rw-r--r--sound/soc/davinci/davinci-pcm.c558
-rw-r--r--sound/soc/davinci/davinci-pcm.h1
-rw-r--r--sound/soc/fsl/mpc5200_dma.c123
-rw-r--r--sound/soc/fsl/mpc5200_dma.h24
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c39
-rw-r--r--sound/soc/omap/Kconfig36
-rw-r--r--sound/soc/omap/Makefile4
-rw-r--r--sound/soc/omap/am3517evm.c202
-rw-r--r--sound/soc/omap/igep0020.c148
-rw-r--r--sound/soc/omap/omap-mcbsp.c63
-rw-r--r--sound/soc/omap/omap3evm.c9
-rw-r--r--sound/soc/omap/omap3pandora.c27
-rw-r--r--sound/soc/omap/overo.c4
-rw-r--r--sound/soc/s3c24xx/Kconfig3
-rw-r--r--sound/soc/s3c24xx/Makefile4
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c2
-rw-r--r--sound/soc/s3c24xx/ln2440sbc_alc650.c2
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c2
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c2
-rw-r--r--sound/soc/s3c24xx/s3c-dma.c (renamed from sound/soc/s3c24xx/s3c24xx-pcm.c)98
-rw-r--r--sound/soc/s3c24xx/s3c-dma.h (renamed from sound/soc/s3c24xx/s3c24xx-pcm.h)8
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c4
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h4
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.c552
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.h123
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c6
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c12
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c12
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_hermes.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c2
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c8
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c2
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c19
-rw-r--r--sound/soc/s6000/s6000-pcm.c4
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/sh/fsi.c234
-rw-r--r--sound/soc/soc-core.c511
-rw-r--r--sound/soc/soc-dapm.c20
-rw-r--r--sound/soc/soc-jack.c3
-rw-r--r--sound/soc/soc-utils.c68
-rw-r--r--sound/usb/caiaq/audio.c16
-rw-r--r--sound/usb/caiaq/device.c2
125 files changed, 3427 insertions, 1619 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index dc78272fc39..1f0f8213e2d 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -937,6 +937,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci)
struct snd_ac97 *ac97;
int ret;
+ writel(0, aaci->base + AC97_POWERDOWN);
/*
* Assert AACIRESET for 2us
*/
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 0c1440121c2..c69c60b2a48 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -953,11 +953,12 @@ static int snd_pcm_dev_register(struct snd_device *device)
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
char str[16];
- struct snd_pcm *pcm = device->device_data;
+ struct snd_pcm *pcm;
struct device *dev;
- if (snd_BUG_ON(!pcm || !device))
+ if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
+ pcm = device->device_data;
mutex_lock(&register_mutex);
err = snd_pcm_add(pcm);
if (err) {
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 6ba066c41d2..252e04ce602 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -165,7 +165,7 @@ MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
module_param_array(pcm_devs, int, NULL, 0444);
MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
module_param_array(pcm_substreams, int, NULL, 0444);
-MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
//module_param_array(midi_devs, int, NULL, 0444);
//MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
module_param(fake_buffer, bool, 0444);
@@ -808,8 +808,6 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
unsigned int idx;
int err;
- if (snd_BUG_ON(!dummy))
- return -EINVAL;
spin_lock_init(&dummy->mixer_lock);
strcpy(card->mixername, "Dummy Mixer");
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 6e7d09ae0e8..7d722a025d0 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -29,6 +29,8 @@ extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
extern int use_internal_drums;
+static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
+ struct snd_midi_channel *chan);
/*
* The next table looks magical, but it certainly is not. Its values have
* been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception
@@ -242,16 +244,20 @@ void snd_opl3_timer_func(unsigned long data)
int again = 0;
int i;
- spin_lock_irqsave(&opl3->sys_timer_lock, flags);
+ spin_lock_irqsave(&opl3->voice_lock, flags);
for (i = 0; i < opl3->max_voices; i++) {
struct snd_opl3_voice *vp = &opl3->voices[i];
if (vp->state > 0 && vp->note_off_check) {
if (vp->note_off == jiffies)
- snd_opl3_note_off(opl3, vp->note, 0, vp->chan);
+ snd_opl3_note_off_unsafe(opl3, vp->note, 0,
+ vp->chan);
else
again++;
}
}
+ spin_unlock_irqrestore(&opl3->voice_lock, flags);
+
+ spin_lock_irqsave(&opl3->sys_timer_lock, flags);
if (again) {
opl3->tlist.expires = jiffies + 1; /* invoke again */
add_timer(&opl3->tlist);
@@ -658,15 +664,14 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
/*
* Release a note in response to a midi note off.
*/
-void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
+static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
+ struct snd_midi_channel *chan)
{
struct snd_opl3 *opl3;
int voice;
struct snd_opl3_voice *vp;
- unsigned long flags;
-
opl3 = p;
#ifdef DEBUG_MIDI
@@ -674,12 +679,9 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
chan->number, chan->midi_program, note);
#endif
- spin_lock_irqsave(&opl3->voice_lock, flags);
-
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
if (chan->drum_channel && use_internal_drums) {
snd_opl3_drum_switch(opl3, note, vel, 0, chan);
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}
/* this loop will hopefully kill all extra voices, because
@@ -697,6 +699,16 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
snd_opl3_kill_voice(opl3, voice);
}
}
+}
+
+void snd_opl3_note_off(void *p, int note, int vel,
+ struct snd_midi_channel *chan)
+{
+ struct snd_opl3 *opl3 = p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&opl3->voice_lock, flags);
+ snd_opl3_note_off_unsafe(p, note, vel, chan);
spin_unlock_irqrestore(&opl3->voice_lock, flags);
}
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 84cc2658c05..e1145ac6e90 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -39,25 +39,20 @@ static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
/* write the port and returns the next expire time in ns;
* called at the trigger-start and in hrtimer callback
*/
-static unsigned long pcsp_timer_update(struct hrtimer *handle)
+static u64 pcsp_timer_update(struct snd_pcsp *chip)
{
unsigned char timer_cnt, val;
u64 ns;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
- struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
unsigned long flags;
if (chip->thalf) {
outb(chip->val61, 0x61);
chip->thalf = 0;
- if (!atomic_read(&chip->timer_active))
- return 0;
return chip->ns_rem;
}
- if (!atomic_read(&chip->timer_active))
- return 0;
substream = chip->playback_substream;
if (!substream)
return 0;
@@ -88,24 +83,17 @@ static unsigned long pcsp_timer_update(struct hrtimer *handle)
return ns;
}
-enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+static void pcsp_pointer_update(struct snd_pcsp *chip)
{
- struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
struct snd_pcm_substream *substream;
- int periods_elapsed, pointer_update;
size_t period_bytes, buffer_bytes;
- unsigned long ns;
+ int periods_elapsed;
unsigned long flags;
- pointer_update = !chip->thalf;
- ns = pcsp_timer_update(handle);
- if (!ns)
- return HRTIMER_NORESTART;
-
/* update the playback position */
substream = chip->playback_substream;
if (!substream)
- return HRTIMER_NORESTART;
+ return;
period_bytes = snd_pcm_lib_period_bytes(substream);
buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
@@ -134,6 +122,26 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
if (periods_elapsed)
tasklet_schedule(&pcsp_pcm_tasklet);
+}
+
+enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
+{
+ struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+ int pointer_update;
+ u64 ns;
+
+ if (!atomic_read(&chip->timer_active) || !chip->playback_substream)
+ return HRTIMER_NORESTART;
+
+ pointer_update = !chip->thalf;
+ ns = pcsp_timer_update(chip);
+ if (!ns) {
+ printk(KERN_WARNING "PCSP: unexpected stop\n");
+ return HRTIMER_NORESTART;
+ }
+
+ if (pointer_update)
+ pcsp_pointer_update(chip);
hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));
@@ -142,8 +150,6 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
static int pcsp_start_playing(struct snd_pcsp *chip)
{
- unsigned long ns;
-
#if PCSP_DEBUG
printk(KERN_INFO "PCSP: start_playing called\n");
#endif
@@ -159,11 +165,7 @@ static int pcsp_start_playing(struct snd_pcsp *chip)
atomic_set(&chip->timer_active, 1);
chip->thalf = 0;
- ns = pcsp_timer_update(&pcsp_chip.timer);
- if (!ns)
- return -EIO;
-
- hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL);
+ hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
return 0;
}
@@ -232,21 +234,22 @@ static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
+ pcsp_sync_stop(chip);
+ chip->playback_ptr = 0;
+ chip->period_ptr = 0;
+ chip->fmt_size =
+ snd_pcm_format_physical_width(substream->runtime->format) >> 3;
+ chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
#if PCSP_DEBUG
printk(KERN_INFO "PCSP: prepare called, "
- "size=%zi psize=%zi f=%zi f1=%i\n",
+ "size=%zi psize=%zi f=%zi f1=%i fsize=%i\n",
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream),
snd_pcm_lib_buffer_bytes(substream) /
snd_pcm_lib_period_bytes(substream),
- substream->runtime->periods);
+ substream->runtime->periods,
+ chip->fmt_size);
#endif
- pcsp_sync_stop(chip);
- chip->playback_ptr = 0;
- chip->period_ptr = 0;
- chip->fmt_size =
- snd_pcm_format_physical_width(substream->runtime->format) >> 3;
- chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
return 0;
}
diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c
index 199b0337714..903bc846763 100644
--- a/sound/drivers/pcsp/pcsp_mixer.c
+++ b/sound/drivers/pcsp/pcsp_mixer.c
@@ -72,7 +72,7 @@ static int pcsp_treble_put(struct snd_kcontrol *kcontrol,
if (treble != chip->treble) {
chip->treble = treble;
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: rate set to %i\n", PCSP_RATE());
+ printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE());
#endif
changed = 1;
}
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index e924492df21..f47f9e226b0 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -624,6 +624,9 @@ snd_harmony_pcm_init(struct snd_harmony *h)
struct snd_pcm *pcm;
int err;
+ if (snd_BUG_ON(!h))
+ return -EINVAL;
+
harmony_disable_interrupts(h);
err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm);
@@ -865,11 +868,12 @@ snd_harmony_mixer_reset(struct snd_harmony *h)
static int __devinit
snd_harmony_mixer_init(struct snd_harmony *h)
{
- struct snd_card *card = h->card;
+ struct snd_card *card;
int idx, err;
if (snd_BUG_ON(!h))
return -EINVAL;
+ card = h->card;
strcpy(card->mixername, "Harmony Gain control interface");
for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index fb5ee3cc396..75c602b5b13 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -259,7 +259,6 @@ config SND_CS5530
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
- depends on X86 && !X86_64
select SND_PCM
select SND_AC97_CODEC
help
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index b458d208720..aaf4da68969 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -973,7 +973,7 @@ static void snd_ali_free_voice(struct snd_ali * codec,
void *private_data;
snd_ali_printk("free_voice: channel=%d\n",pvoice->number);
- if (pvoice == NULL || !pvoice->use)
+ if (!pvoice->use)
return;
snd_ali_clear_voices(codec, pvoice->number, pvoice->number);
spin_lock_irq(&codec->voice_alloc);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 24585c6c6d0..4e2b925a94c 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -808,6 +808,8 @@ static struct pci_device_id snd_bt87x_ids[] = {
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC),
/* Leadtek Winfast tv 2000xp delux */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
+ /* Pinnacle PCTV */
+ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x11bd, 0x0012, GENERIC),
/* Voodoo TV 200 */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
/* Askey Computer Corp. MagicTView'99 */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c9ad182e1b4..e340792f6cb 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2674,6 +2674,7 @@ static struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
+ { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index c8435c9a97f..9fb60276f5c 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -29,6 +29,9 @@
#include "hda_codec.h"
#include "hda_local.h"
+/* define below to restrict the supported rates and formats */
+/* #define LIMITED_RATE_FMT_SUPPORT */
+
struct nvhdmi_spec {
struct hda_multi_out multiout;
@@ -60,6 +63,22 @@ static struct hda_verb nvhdmi_basic_init[] = {
{} /* terminator */
};
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS 16
+#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+ (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS 24
+#define SUPPORTED_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
/*
* Controls
*/
@@ -258,9 +277,9 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = {
.channels_min = 2,
.channels_max = 8,
.nid = Nv_Master_Convert_nid,
- .rates = SNDRV_PCM_RATE_48000,
- .maxbps = 16,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
.ops = {
.open = nvhdmi_dig_playback_pcm_open,
.close = nvhdmi_dig_playback_pcm_close_8ch,
@@ -273,9 +292,9 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
.channels_min = 2,
.channels_max = 2,
.nid = Nv_Master_Convert_nid,
- .rates = SNDRV_PCM_RATE_48000,
- .maxbps = 16,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
.ops = {
.open = nvhdmi_dig_playback_pcm_open,
.close = nvhdmi_dig_playback_pcm_close_2ch,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7810d3dcad8..ff20048504b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -275,7 +275,7 @@ struct alc_spec {
struct snd_kcontrol_new *cap_mixer; /* capture mixer */
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
- const struct hda_verb *init_verbs[5]; /* initialization verbs
+ const struct hda_verb *init_verbs[10]; /* initialization verbs
* don't forget NULL
* termination!
*/
@@ -965,6 +965,8 @@ static void alc_automute_pin(struct hda_codec *codec)
unsigned int nid = spec->autocfg.hp_pins[0];
int i;
+ if (!nid)
+ return;
pincap = snd_hda_query_pin_caps(codec, nid);
if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
@@ -1332,15 +1334,20 @@ do_sku:
* when the external headphone out jack is plugged"
*/
if (!spec->autocfg.hp_pins[0]) {
+ hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
- spec->autocfg.hp_pins[0] = porta;
+ nid = porta;
else if (tmp == 1)
- spec->autocfg.hp_pins[0] = porte;
+ nid = porte;
else if (tmp == 2)
- spec->autocfg.hp_pins[0] = portd;
+ nid = portd;
else
return 1;
+ for (i = 0; i < spec->autocfg.line_outs; i++)
+ if (spec->autocfg.line_out_pins[i] == nid)
+ return 1;
+ spec->autocfg.hp_pins[0] = nid;
}
alc_init_auto_hp(codec);
@@ -1362,7 +1369,7 @@ static void alc_ssid_check(struct hda_codec *codec,
}
/*
- * Fix-up pin default configurations
+ * Fix-up pin default configurations and add default verbs
*/
struct alc_pincfg {
@@ -1370,9 +1377,14 @@ struct alc_pincfg {
u32 val;
};
-static void alc_fix_pincfg(struct hda_codec *codec,
+struct alc_fixup {
+ const struct alc_pincfg *pins;
+ const struct hda_verb *verbs;
+};
+
+static void alc_pick_fixup(struct hda_codec *codec,
const struct snd_pci_quirk *quirk,
- const struct alc_pincfg **pinfix)
+ const struct alc_fixup *fix)
{
const struct alc_pincfg *cfg;
@@ -1380,9 +1392,14 @@ static void alc_fix_pincfg(struct hda_codec *codec,
if (!quirk)
return;
- cfg = pinfix[quirk->value];
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+ fix += quirk->value;
+ cfg = fix->pins;
+ if (cfg) {
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+ }
+ if (fix->verbs)
+ add_verb(codec->spec, fix->verbs);
}
/*
@@ -9593,11 +9610,13 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
{ }
};
-static const struct alc_pincfg *alc882_pin_fixes[] = {
- [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+static const struct alc_fixup alc882_fixups[] = {
+ [PINFIX_ABIT_AW9D_MAX] = {
+ .pins = alc882_abit_aw9d_pinfix
+ },
};
-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
{}
};
@@ -9869,7 +9888,7 @@ static int patch_alc882(struct hda_codec *codec)
board_config = ALC882_AUTO;
}
- alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+ alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
@@ -12585,7 +12604,8 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
ALC268_ACER_ASPIRE_ONE),
SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
- SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
+ SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
+ "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
/* almost compatible with toshiba but with optional digital outs;
* auto-probing seems working fine
*/
@@ -12842,12 +12862,15 @@ static int patch_alc268(struct hda_codec *codec)
unsigned int wcap = get_wcaps(codec, 0x07);
int i;
+ spec->capsrc_nids = alc268_capsrc_nids;
/* get type */
wcap = get_wcaps_type(wcap);
if (spec->auto_mic ||
wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
spec->adc_nids = alc268_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
+ if (spec->auto_mic)
+ fixup_automic_adc(codec);
if (spec->auto_mic || spec->input_mux->num_items == 1)
add_mixer(spec, alc268_capture_nosrc_mixer);
else
@@ -12857,7 +12880,6 @@ static int patch_alc268(struct hda_codec *codec)
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
add_mixer(spec, alc268_capture_mixer);
}
- spec->capsrc_nids = alc268_capsrc_nids;
/* set default input source */
for (i = 0; i < spec->num_adc_nids; i++)
snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
@@ -14357,15 +14379,16 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
static void alc861_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
- pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
+ if (spec->autocfg.hp_outs)
+ alc861_auto_set_output_and_unmute(codec,
+ spec->autocfg.hp_pins[0],
+ PIN_HP,
spec->multiout.hp_nid);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+ if (spec->autocfg.speaker_outs)
+ alc861_auto_set_output_and_unmute(codec,
+ spec->autocfg.speaker_pins[0],
+ PIN_OUT,
spec->multiout.dac_nids[0]);
}
@@ -15158,7 +15181,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
- SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+ /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
@@ -15551,6 +15574,29 @@ static void alc861vd_auto_init(struct hda_codec *codec)
alc_inithook(codec);
}
+enum {
+ ALC660VD_FIX_ASUS_GPIO1
+};
+
+/* reset GPIO1 */
+static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+ { }
+};
+
+static const struct alc_fixup alc861vd_fixups[] = {
+ [ALC660VD_FIX_ASUS_GPIO1] = {
+ .verbs = alc660vd_fix_asus_gpio1_verbs,
+ },
+};
+
+static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+ {}
+};
+
static int patch_alc861vd(struct hda_codec *codec)
{
struct alc_spec *spec;
@@ -15572,6 +15618,8 @@ static int patch_alc861vd(struct hda_codec *codec)
board_config = ALC861VD_AUTO;
}
+ alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
+
if (board_config == ALC861VD_AUTO) {
/* automatic parse from the BIOS config */
err = alc861vd_parse_auto_config(codec);
@@ -17329,7 +17377,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
/* create playback/capture controls for input pins */
#define alc662_auto_create_input_ctls \
- alc880_auto_create_input_ctls
+ alc882_auto_create_input_ctls
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid, int pin_type,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index a9b26828a65..66c0876bf73 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -158,6 +158,7 @@ enum {
STAC_D965_5ST_NO_FP,
STAC_DELL_3ST,
STAC_DELL_BIOS,
+ STAC_927X_VOLKNOB,
STAC_927X_MODELS
};
@@ -907,6 +908,16 @@ static struct hda_verb d965_core_init[] = {
{}
};
+static struct hda_verb dell_3st_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* unmute node 0x1b */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* select node 0x03 as DAC */
+ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {}
+};
+
static struct hda_verb stac927x_core_init[] = {
/* set master volume and direct control */
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -915,6 +926,14 @@ static struct hda_verb stac927x_core_init[] = {
{}
};
+static struct hda_verb stac927x_volknob_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* enable analog pc beep path */
+ {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+ {}
+};
+
static struct hda_verb stac9205_core_init[] = {
/* set master volume and direct control */
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -1999,6 +2018,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
[STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs,
[STAC_DELL_3ST] = dell_3st_pin_configs,
[STAC_DELL_BIOS] = NULL,
+ [STAC_927X_VOLKNOB] = NULL,
};
static const char *stac927x_models[STAC_927X_MODELS] = {
@@ -2010,6 +2030,7 @@ static const char *stac927x_models[STAC_927X_MODELS] = {
[STAC_D965_5ST_NO_FP] = "5stack-no-fp",
[STAC_DELL_3ST] = "dell-3stack",
[STAC_DELL_BIOS] = "dell-bios",
+ [STAC_927X_VOLKNOB] = "volknob",
};
static struct snd_pci_quirk stac927x_cfg_tbl[] = {
@@ -2045,6 +2066,8 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
"Intel D965", STAC_D965_5ST),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
"Intel D965", STAC_D965_5ST),
+ /* volume-knob fixes */
+ SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
{} /* terminator */
};
@@ -5612,10 +5635,14 @@ static int patch_stac927x(struct hda_codec *codec)
spec->dmic_nids = stac927x_dmic_nids;
spec->num_dmics = STAC927X_NUM_DMICS;
- spec->init = d965_core_init;
+ spec->init = dell_3st_core_init;
spec->dmux_nids = stac927x_dmux_nids;
spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
break;
+ case STAC_927X_VOLKNOB:
+ spec->num_dmics = 0;
+ spec->init = stac927x_volknob_core_init;
+ break;
default:
spec->num_dmics = 0;
spec->init = stac927x_core_init;
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
index 37564300b50..6da21a2bcad 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -52,11 +52,13 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
/* only use basic functionality for now */
- ice->num_total_dacs = 2; /* only PSDOUT0 is connected */
+ /* VT1616 6ch codec connected to PSDOUT0 using packed mode */
+ ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
- /* Chaintech AV-710 has another codecs, which need initialization */
- /* initialize WM8728 codec */
+ /* Chaintech AV-710 has another WM8728 codec connected to PSDOUT4
+ (shared with the SPDIF output). Mixer control for this codec
+ is not yet supported. */
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) {
for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
wm_put(ice, wm_inits[i], wm_inits[i+1]);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index cecf1ffeeaa..d74033a2cfb 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2259,7 +2259,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
}
static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = snd_ice1712_pro_peak_info,
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index af6e0014862..10fc92c0557 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -648,7 +648,7 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
(inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
/* running? we cannot change the rate now... */
spin_unlock_irqrestore(&ice->reg_lock, flags);
- return -EBUSY;
+ return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
}
if (!force && is_pro_rate_locked(ice)) {
spin_unlock_irqrestore(&ice->reg_lock, flags);
@@ -1294,7 +1294,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci),
- 64*1024, 64*1024);
+ 256*1024, 256*1024);
ice->pcm = pcm;
@@ -1408,7 +1408,7 @@ static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci),
- 64*1024, 64*1024);
+ 256*1024, 256*1024);
ice->pcm_ds = pcm;
@@ -2110,7 +2110,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
}
static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = snd_vt1724_pro_peak_info,
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index acfa4760da4..8a332d2f615 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -386,6 +386,7 @@ struct via82xx {
struct snd_pcm *pcms[2];
struct snd_rawmidi *rmidi;
+ struct snd_kcontrol *dxs_controls[4];
struct snd_ac97_bus *ac97_bus;
struct snd_ac97 *ac97;
@@ -1216,9 +1217,9 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
/*
- * open callback for playback on via686 and via823x DSX
+ * open callback for playback on via686
*/
-static int snd_via82xx_playback_open(struct snd_pcm_substream *substream)
+static int snd_via686_playback_open(struct snd_pcm_substream *substream)
{
struct via82xx *chip = snd_pcm_substream_chip(substream);
struct viadev *viadev = &chip->devs[chip->playback_devno + substream->number];
@@ -1230,6 +1231,32 @@ static int snd_via82xx_playback_open(struct snd_pcm_substream *substream)
}
/*
+ * open callback for playback on via823x DXS
+ */
+static int snd_via8233_playback_open(struct snd_pcm_substream *substream)
+{
+ struct via82xx *chip = snd_pcm_substream_chip(substream);
+ struct viadev *viadev;
+ unsigned int stream;
+ int err;
+
+ viadev = &chip->devs[chip->playback_devno + substream->number];
+ if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0)
+ return err;
+ stream = viadev->reg_offset / 0x10;
+ if (chip->dxs_controls[stream]) {
+ chip->playback_volume[stream][0] = 0;
+ chip->playback_volume[stream][1] = 0;
+ chip->dxs_controls[stream]->vd[0].access &=
+ ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &chip->dxs_controls[stream]->id);
+ }
+ return 0;
+}
+
+/*
* open callback for playback on via823x multi-channel
*/
static int snd_via8233_multi_open(struct snd_pcm_substream *substream)
@@ -1302,10 +1329,26 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_via8233_playback_close(struct snd_pcm_substream *substream)
+{
+ struct via82xx *chip = snd_pcm_substream_chip(substream);
+ struct viadev *viadev = substream->runtime->private_data;
+ unsigned int stream;
+
+ stream = viadev->reg_offset / 0x10;
+ if (chip->dxs_controls[stream]) {
+ chip->dxs_controls[stream]->vd[0].access |=
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO,
+ &chip->dxs_controls[stream]->id);
+ }
+ return snd_via82xx_pcm_close(substream);
+}
+
/* via686 playback callbacks */
static struct snd_pcm_ops snd_via686_playback_ops = {
- .open = snd_via82xx_playback_open,
+ .open = snd_via686_playback_open,
.close = snd_via82xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
@@ -1331,8 +1374,8 @@ static struct snd_pcm_ops snd_via686_capture_ops = {
/* via823x DSX playback callbacks */
static struct snd_pcm_ops snd_via8233_playback_ops = {
- .open = snd_via82xx_playback_open,
- .close = snd_via82xx_pcm_close,
+ .open = snd_via8233_playback_open,
+ .close = snd_via8233_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
@@ -1626,7 +1669,7 @@ static int snd_via8233_dxs_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct via82xx *chip = snd_kcontrol_chip(kcontrol);
- unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+ unsigned int idx = kcontrol->id.subdevice;
ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0];
ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1];
@@ -1646,7 +1689,7 @@ static int snd_via8233_dxs_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct via82xx *chip = snd_kcontrol_chip(kcontrol);
- unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+ unsigned int idx = kcontrol->id.subdevice;
unsigned long port = chip->port + 0x10 * idx;
unsigned char val;
int i, change = 0;
@@ -1705,11 +1748,13 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata =
};
static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = {
- .name = "VIA DXS Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- .count = 4,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .device = 0,
+ /* .subdevice set later */
+ .name = "PCM Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.info = snd_via8233_dxs_volume_info,
.get = snd_via8233_dxs_volume_get,
.put = snd_via8233_dxs_volume_put,
@@ -1936,10 +1981,19 @@ static int __devinit snd_via8233_init_misc(struct via82xx *chip)
}
else /* Using DXS when PCM emulation is enabled is really weird */
{
- /* Standalone DXS controls */
- err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
- if (err < 0)
- return err;
+ for (i = 0; i < 4; ++i) {
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_ctl_new1(
+ &snd_via8233_dxs_volume_control, chip);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.subdevice = i;
+ err = snd_ctl_add(chip->card, kctl);
+ if (err < 0)
+ return err;
+ chip->dxs_controls[i] = kctl;
+ }
}
}
/* select spdif data slot 10/11 */
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 7dea74b71cf..64b859925c0 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -217,20 +217,25 @@ static void snd_pdacf_detach(struct pcmcia_device *link)
* configuration callback
*/
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
static int pdacf_config(struct pcmcia_device *link)
{
struct snd_pdacf *pdacf = link->priv;
- int last_fn, last_ret;
+ int ret;
snd_printdd(KERN_DEBUG "pdacf_config called\n");
link->conf.ConfigIndex = 0x5;
- CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
- CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+ ret = pcmcia_request_io(link, &link->io);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_request_irq(link, &link->irq);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if (ret)
+ goto failed;
if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
goto failed;
@@ -238,8 +243,6 @@ static int pdacf_config(struct pcmcia_device *link)
link->dev_node = &pdacf->node;
return 0;
-cs_failed:
- cs_error(link, last_fn, last_ret);
failed:
pcmcia_disable_device(link);
return -ENODEV;
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 7445cc8a47d..1492744ad67 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -213,14 +213,11 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq
* configuration callback
*/
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
static int vxpocket_config(struct pcmcia_device *link)
{
struct vx_core *chip = link->priv;
struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
- int last_fn, last_ret;
+ int ret;
snd_printdd(KERN_DEBUG "vxpocket_config called\n");
@@ -235,9 +232,17 @@ static int vxpocket_config(struct pcmcia_device *link)
strcpy(chip->card->driver, vxp440_hw.name);
}
- CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
- CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+ ret = pcmcia_request_io(link, &link->io);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_request_irq(link, &link->irq);
+ if (ret)
+ goto failed;
+
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if (ret)
+ goto failed;
chip->dev = &handle_to_dev(link);
snd_card_set_dev(chip->card, chip->dev);
@@ -248,8 +253,6 @@ static int vxpocket_config(struct pcmcia_device *link)
link->dev_node = &vxp->node;
return 0;
-cs_failed:
- cs_error(link, last_fn, last_ret);
failed:
pcmcia_disable_device(link);
return -ENODEV;
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
index bd2338ab2ce..0519c60f5be 100644
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -2,7 +2,7 @@
menuconfig SND_PPC
bool "PowerPC sound devices"
- depends on PPC64 || PPC32
+ depends on PPC
default y
help
Support for sound devices specific to PowerPC architectures.
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0c5eac01bf2..1470141d416 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 594c6c5b783..fe9f4657c95 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -2,7 +2,7 @@
* Au12x0/Au1550 PSC ALSA ASoC audio support.
*
* (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- * Manuel Lauss <mano@roarinelk.homelinux.net>
+ * Manuel Lauss <manuel.lauss@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -333,6 +333,30 @@ static int au1xpsc_pcm_new(struct snd_card *card,
static int au1xpsc_pcm_probe(struct platform_device *pdev)
{
+ if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
+ return -ENODEV;
+
+ return 0;
+}
+
+static int au1xpsc_pcm_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+/* au1xpsc audio platform */
+struct snd_soc_platform au1xpsc_soc_platform = {
+ .name = "au1xpsc-pcm-dbdma",
+ .probe = au1xpsc_pcm_probe,
+ .remove = au1xpsc_pcm_remove,
+ .pcm_ops = &au1xpsc_pcm_ops,
+ .pcm_new = au1xpsc_pcm_new,
+ .pcm_free = au1xpsc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
+
+static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
+{
struct resource *r;
int ret;
@@ -365,7 +389,9 @@ static int au1xpsc_pcm_probe(struct platform_device *pdev)
}
(au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
- return 0;
+ ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+ if (!ret)
+ return ret;
out2:
kfree(au1xpsc_audio_pcmdma[PCM_RX]);
@@ -376,10 +402,12 @@ out1:
return ret;
}
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
+static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
{
int i;
+ snd_soc_unregister_platform(&au1xpsc_soc_platform);
+
for (i = 0; i < 2; i++) {
if (au1xpsc_audio_pcmdma[i]) {
au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
@@ -391,32 +419,83 @@ static int au1xpsc_pcm_remove(struct platform_device *pdev)
return 0;
}
-/* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
- .name = "au1xpsc-pcm-dbdma",
- .probe = au1xpsc_pcm_probe,
- .remove = au1xpsc_pcm_remove,
- .pcm_ops = &au1xpsc_pcm_ops,
- .pcm_new = au1xpsc_pcm_new,
- .pcm_free = au1xpsc_pcm_free_dma_buffers,
+static struct platform_driver au1xpsc_pcm_driver = {
+ .driver = {
+ .name = "au1xpsc-pcm",
+ .owner = THIS_MODULE,
+ },
+ .probe = au1xpsc_pcm_drvprobe,
+ .remove = __devexit_p(au1xpsc_pcm_drvremove),
};
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
-static int __init au1xpsc_audio_dbdma_init(void)
+static int __init au1xpsc_audio_dbdma_load(void)
{
au1xpsc_audio_pcmdma[PCM_TX] = NULL;
au1xpsc_audio_pcmdma[PCM_RX] = NULL;
- return snd_soc_register_platform(&au1xpsc_soc_platform);
+ return platform_driver_register(&au1xpsc_pcm_driver);
}
-static void __exit au1xpsc_audio_dbdma_exit(void)
+static void __exit au1xpsc_audio_dbdma_unload(void)
{
- snd_soc_unregister_platform(&au1xpsc_soc_platform);
+ platform_driver_unregister(&au1xpsc_pcm_driver);
+}
+
+module_init(au1xpsc_audio_dbdma_load);
+module_exit(au1xpsc_audio_dbdma_unload);
+
+
+struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
+{
+ struct resource *res, *r;
+ struct platform_device *pd;
+ int id[2];
+ int ret;
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r)
+ return NULL;
+ id[0] = r->start;
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!r)
+ return NULL;
+ id[1] = r->start;
+
+ res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ res[0].start = res[0].end = id[0];
+ res[1].start = res[1].end = id[1];
+ res[0].flags = res[1].flags = IORESOURCE_DMA;
+
+ pd = platform_device_alloc("au1xpsc-pcm", -1);
+ if (!pd)
+ goto out;
+
+ pd->resource = res;
+ pd->num_resources = 2;
+
+ ret = platform_device_add(pd);
+ if (!ret)
+ return pd;
+
+out:
+ kfree(res);
+ return NULL;
}
+EXPORT_SYMBOL_GPL(au1xpsc_pcm_add);
-module_init(au1xpsc_audio_dbdma_init);
-module_exit(au1xpsc_audio_dbdma_exit);
+void au1xpsc_pcm_destroy(struct platform_device *dmapd)
+{
+ if (dmapd) {
+ kfree(dmapd->resource);
+ dmapd->resource = NULL;
+ platform_device_unregister(dmapd);
+ }
+}
+EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 2a06a9c548a..340311d7fed 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -317,19 +317,55 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
static int au1xpsc_ac97_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
+ return au1xpsc_ac97_workdata ? 0 : -ENODEV;
+}
+
+static void au1xpsc_ac97_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+ .trigger = au1xpsc_ac97_trigger,
+ .hw_params = au1xpsc_ac97_hw_params,
+};
+
+struct snd_soc_dai au1xpsc_ac97_dai = {
+ .name = "au1xpsc_ac97",
+ .ac97_control = 1,
+ .probe = au1xpsc_ac97_probe,
+ .remove = au1xpsc_ac97_remove,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &au1xpsc_ac97_dai_ops,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
+
+static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
+{
int ret;
struct resource *r;
unsigned long sel;
+ struct au1xpsc_audio_data *wd;
if (au1xpsc_ac97_workdata)
return -EBUSY;
- au1xpsc_ac97_workdata =
- kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
- if (!au1xpsc_ac97_workdata)
+ wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+ if (!wd)
return -ENOMEM;
- mutex_init(&au1xpsc_ac97_workdata->lock);
+ mutex_init(&wd->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -338,81 +374,95 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev,
}
ret = -EBUSY;
- au1xpsc_ac97_workdata->ioarea =
- request_mem_region(r->start, r->end - r->start + 1,
+ wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
"au1xpsc_ac97");
- if (!au1xpsc_ac97_workdata->ioarea)
+ if (!wd->ioarea)
goto out0;
- au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff);
- if (!au1xpsc_ac97_workdata->mmio)
+ wd->mmio = ioremap(r->start, 0xffff);
+ if (!wd->mmio)
goto out1;
/* configuration: max dma trigger threshold, enable ac97 */
- au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 |
- PSC_AC97CFG_TT_FIFO8 |
- PSC_AC97CFG_DE_ENABLE;
+ wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
+ PSC_AC97CFG_DE_ENABLE;
- /* preserve PSC clock source set up by platform (dev.platform_data
- * is already occupied by soc layer)
- */
- sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK;
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+ /* preserve PSC clock source set up by platform */
+ sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK;
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
- au_writel(0, PSC_SEL(au1xpsc_ac97_workdata));
+ au_writel(0, PSC_SEL(wd));
au_sync();
- au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata));
+ au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
au_sync();
- /* next up: cold reset. Dont check for PSC-ready now since
- * there may not be any codec clock yet.
- */
- return 0;
+ ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+ if (ret)
+ goto out1;
+
+ wd->dmapd = au1xpsc_pcm_add(pdev);
+ if (wd->dmapd) {
+ platform_set_drvdata(pdev, wd);
+ au1xpsc_ac97_workdata = wd; /* MDEV */
+ return 0;
+ }
+ snd_soc_unregister_dai(&au1xpsc_ac97_dai);
out1:
- release_resource(au1xpsc_ac97_workdata->ioarea);
- kfree(au1xpsc_ac97_workdata->ioarea);
+ release_resource(wd->ioarea);
+ kfree(wd->ioarea);
out0:
- kfree(au1xpsc_ac97_workdata);
- au1xpsc_ac97_workdata = NULL;
+ kfree(wd);
return ret;
}
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
{
+ struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+
+ if (wd->dmapd)
+ au1xpsc_pcm_destroy(wd->dmapd);
+
+ snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+
/* disable PSC completely */
- au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+ au_writel(0, AC97_CFG(wd));
au_sync();
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
- iounmap(au1xpsc_ac97_workdata->mmio);
- release_resource(au1xpsc_ac97_workdata->ioarea);
- kfree(au1xpsc_ac97_workdata->ioarea);
- kfree(au1xpsc_ac97_workdata);
- au1xpsc_ac97_workdata = NULL;
+ iounmap(wd->mmio);
+ release_resource(wd->ioarea);
+ kfree(wd->ioarea);
+ kfree(wd);
+
+ au1xpsc_ac97_workdata = NULL; /* MDEV */
+
+ return 0;
}
-static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai)
+#ifdef CONFIG_PM
+static int au1xpsc_ac97_drvsuspend(struct device *dev)
{
+ struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
/* save interesting registers and disable PSC */
- au1xpsc_ac97_workdata->pm[0] =
- au_readl(PSC_SEL(au1xpsc_ac97_workdata));
+ wd->pm[0] = au_readl(PSC_SEL(wd));
- au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+ au_writel(0, AC97_CFG(wd));
au_sync();
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
return 0;
}
-static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
+static int au1xpsc_ac97_drvresume(struct device *dev)
{
+ struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
/* restore PSC clock config */
- au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE,
- PSC_SEL(au1xpsc_ac97_workdata));
+ au_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd));
au_sync();
/* after this point the ac97 core will cold-reset the codec.
@@ -422,48 +472,44 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
- .trigger = au1xpsc_ac97_trigger,
- .hw_params = au1xpsc_ac97_hw_params,
+static struct dev_pm_ops au1xpscac97_pmops = {
+ .suspend = au1xpsc_ac97_drvsuspend,
+ .resume = au1xpsc_ac97_drvresume,
};
-struct snd_soc_dai au1xpsc_ac97_dai = {
- .name = "au1xpsc_ac97",
- .ac97_control = 1,
- .probe = au1xpsc_ac97_probe,
- .remove = au1xpsc_ac97_remove,
- .suspend = au1xpsc_ac97_suspend,
- .resume = au1xpsc_ac97_resume,
- .playback = {
- .rates = AC97_RATES,
- .formats = AC97_FMTS,
- .channels_min = 2,
- .channels_max = 2,
- },
- .capture = {
- .rates = AC97_RATES,
- .formats = AC97_FMTS,
- .channels_min = 2,
- .channels_max = 2,
+#define AU1XPSCAC97_PMOPS &au1xpscac97_pmops
+
+#else
+
+#define AU1XPSCAC97_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xpsc_ac97_driver = {
+ .driver = {
+ .name = "au1xpsc_ac97",
+ .owner = THIS_MODULE,
+ .pm = AU1XPSCAC97_PMOPS,
},
- .ops = &au1xpsc_ac97_dai_ops,
+ .probe = au1xpsc_ac97_drvprobe,
+ .remove = __devexit_p(au1xpsc_ac97_drvremove),
};
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
-static int __init au1xpsc_ac97_init(void)
+static int __init au1xpsc_ac97_load(void)
{
au1xpsc_ac97_workdata = NULL;
- return snd_soc_register_dai(&au1xpsc_ac97_dai);
+ return platform_driver_register(&au1xpsc_ac97_driver);
}
-static void __exit au1xpsc_ac97_exit(void)
+static void __exit au1xpsc_ac97_unload(void)
{
- snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+ platform_driver_unregister(&au1xpsc_ac97_driver);
}
-module_init(au1xpsc_ac97_init);
-module_exit(au1xpsc_ac97_exit);
+module_init(au1xpsc_ac97_load);
+module_exit(au1xpsc_ac97_unload);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
-MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>");
+MODULE_AUTHOR("Manuel Lauss");
+
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index bb589327ee3..0cf2ca61c77 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -2,7 +2,7 @@
* Au12x0/Au1550 PSC ALSA ASoC audio support.
*
* (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- * Manuel Lauss <mano@roarinelk.homelinux.net>
+ * Manuel Lauss <manuel.lauss@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -265,16 +265,52 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
static int au1xpsc_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
+ return au1xpsc_i2s_workdata ? 0 : -ENODEV;
+}
+
+static void au1xpsc_i2s_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+ .trigger = au1xpsc_i2s_trigger,
+ .hw_params = au1xpsc_i2s_hw_params,
+ .set_fmt = au1xpsc_i2s_set_fmt,
+};
+
+struct snd_soc_dai au1xpsc_i2s_dai = {
+ .name = "au1xpsc_i2s",
+ .probe = au1xpsc_i2s_probe,
+ .remove = au1xpsc_i2s_remove,
+ .playback = {
+ .rates = AU1XPSC_I2S_RATES,
+ .formats = AU1XPSC_I2S_FMTS,
+ .channels_min = 2,
+ .channels_max = 8, /* 2 without external help */
+ },
+ .capture = {
+ .rates = AU1XPSC_I2S_RATES,
+ .formats = AU1XPSC_I2S_FMTS,
+ .channels_min = 2,
+ .channels_max = 8, /* 2 without external help */
+ },
+ .ops = &au1xpsc_i2s_dai_ops,
+};
+EXPORT_SYMBOL(au1xpsc_i2s_dai);
+
+static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev)
+{
struct resource *r;
unsigned long sel;
int ret;
+ struct au1xpsc_audio_data *wd;
if (au1xpsc_i2s_workdata)
return -EBUSY;
- au1xpsc_i2s_workdata =
- kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
- if (!au1xpsc_i2s_workdata)
+ wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+ if (!wd)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -284,131 +320,146 @@ static int au1xpsc_i2s_probe(struct platform_device *pdev,
}
ret = -EBUSY;
- au1xpsc_i2s_workdata->ioarea =
- request_mem_region(r->start, r->end - r->start + 1,
+ wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
"au1xpsc_i2s");
- if (!au1xpsc_i2s_workdata->ioarea)
+ if (!wd->ioarea)
goto out0;
- au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff);
- if (!au1xpsc_i2s_workdata->mmio)
+ wd->mmio = ioremap(r->start, 0xffff);
+ if (!wd->mmio)
goto out1;
/* preserve PSC clock source set up by platform (dev.platform_data
* is already occupied by soc layer)
*/
- sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK;
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+ sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK;
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
- au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata));
- au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+ au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd));
+ au_writel(0, I2S_CFG(wd));
au_sync();
/* preconfigure: set max rx/tx fifo depths */
- au1xpsc_i2s_workdata->cfg |=
- PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8;
+ wd->cfg |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8;
/* don't wait for I2S core to become ready now; clocks may not
* be running yet; depending on clock input for PSC a wait might
* time out.
*/
- return 0;
+ ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+ if (ret)
+ goto out1;
+ /* finally add the DMA device for this PSC */
+ wd->dmapd = au1xpsc_pcm_add(pdev);
+ if (wd->dmapd) {
+ platform_set_drvdata(pdev, wd);
+ au1xpsc_i2s_workdata = wd;
+ return 0;
+ }
+
+ snd_soc_unregister_dai(&au1xpsc_i2s_dai);
out1:
- release_resource(au1xpsc_i2s_workdata->ioarea);
- kfree(au1xpsc_i2s_workdata->ioarea);
+ release_resource(wd->ioarea);
+ kfree(wd->ioarea);
out0:
- kfree(au1xpsc_i2s_workdata);
- au1xpsc_i2s_workdata = NULL;
+ kfree(wd);
return ret;
}
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
{
- au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+ struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+
+ if (wd->dmapd)
+ au1xpsc_pcm_destroy(wd->dmapd);
+
+ snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+
+ au_writel(0, I2S_CFG(wd));
au_sync();
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
- iounmap(au1xpsc_i2s_workdata->mmio);
- release_resource(au1xpsc_i2s_workdata->ioarea);
- kfree(au1xpsc_i2s_workdata->ioarea);
- kfree(au1xpsc_i2s_workdata);
- au1xpsc_i2s_workdata = NULL;
+ iounmap(wd->mmio);
+ release_resource(wd->ioarea);
+ kfree(wd->ioarea);
+ kfree(wd);
+
+ au1xpsc_i2s_workdata = NULL; /* MDEV */
+
+ return 0;
}
-static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai)
+#ifdef CONFIG_PM
+static int au1xpsc_i2s_drvsuspend(struct device *dev)
{
+ struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
/* save interesting register and disable PSC */
- au1xpsc_i2s_workdata->pm[0] =
- au_readl(PSC_SEL(au1xpsc_i2s_workdata));
+ wd->pm[0] = au_readl(PSC_SEL(wd));
- au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+ au_writel(0, I2S_CFG(wd));
au_sync();
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
return 0;
}
-static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai)
+static int au1xpsc_i2s_drvresume(struct device *dev)
{
+ struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
+
/* select I2S mode and PSC clock */
- au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
au_sync();
- au_writel(0, PSC_SEL(au1xpsc_i2s_workdata));
+ au_writel(0, PSC_SEL(wd));
au_sync();
- au_writel(au1xpsc_i2s_workdata->pm[0],
- PSC_SEL(au1xpsc_i2s_workdata));
+ au_writel(wd->pm[0], PSC_SEL(wd));
au_sync();
return 0;
}
-static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
- .trigger = au1xpsc_i2s_trigger,
- .hw_params = au1xpsc_i2s_hw_params,
- .set_fmt = au1xpsc_i2s_set_fmt,
+static struct dev_pm_ops au1xpsci2s_pmops = {
+ .suspend = au1xpsc_i2s_drvsuspend,
+ .resume = au1xpsc_i2s_drvresume,
};
-struct snd_soc_dai au1xpsc_i2s_dai = {
- .name = "au1xpsc_i2s",
- .probe = au1xpsc_i2s_probe,
- .remove = au1xpsc_i2s_remove,
- .suspend = au1xpsc_i2s_suspend,
- .resume = au1xpsc_i2s_resume,
- .playback = {
- .rates = AU1XPSC_I2S_RATES,
- .formats = AU1XPSC_I2S_FMTS,
- .channels_min = 2,
- .channels_max = 8, /* 2 without external help */
- },
- .capture = {
- .rates = AU1XPSC_I2S_RATES,
- .formats = AU1XPSC_I2S_FMTS,
- .channels_min = 2,
- .channels_max = 8, /* 2 without external help */
+#define AU1XPSCI2S_PMOPS &au1xpsci2s_pmops
+
+#else
+
+#define AU1XPSCI2S_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xpsc_i2s_driver = {
+ .driver = {
+ .name = "au1xpsc_i2s",
+ .owner = THIS_MODULE,
+ .pm = AU1XPSCI2S_PMOPS,
},
- .ops = &au1xpsc_i2s_dai_ops,
+ .probe = au1xpsc_i2s_drvprobe,
+ .remove = __devexit_p(au1xpsc_i2s_drvremove),
};
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
-static int __init au1xpsc_i2s_init(void)
+static int __init au1xpsc_i2s_load(void)
{
au1xpsc_i2s_workdata = NULL;
- return snd_soc_register_dai(&au1xpsc_i2s_dai);
+ return platform_driver_register(&au1xpsc_i2s_driver);
}
-static void __exit au1xpsc_i2s_exit(void)
+static void __exit au1xpsc_i2s_unload(void)
{
- snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+ platform_driver_unregister(&au1xpsc_i2s_driver);
}
-module_init(au1xpsc_i2s_init);
-module_exit(au1xpsc_i2s_exit);
+module_init(au1xpsc_i2s_load);
+module_exit(au1xpsc_i2s_unload);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 3f474e8ed4f..32d3807d3f5 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -2,7 +2,7 @@
* Au12x0/Au1550 PSC ALSA ASoC audio support.
*
* (c) 2007-2008 MSC Vertriebsges.m.b.H.,
- * Manuel Lauss <mano@roarinelk.homelinux.net>
+ * Manuel Lauss <manuel.lauss@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,10 @@ extern struct snd_soc_dai au1xpsc_i2s_dai;
extern struct snd_soc_platform au1xpsc_soc_platform;
extern struct snd_ac97_bus_ops soc_ac97_ops;
+/* DBDMA helpers */
+extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
+extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
+
struct au1xpsc_audio_data {
void __iomem *mmio;
@@ -30,6 +34,7 @@ struct au1xpsc_audio_data {
unsigned long pm[2];
struct resource *ioarea;
struct mutex lock;
+ struct platform_device *dmapd;
};
#define PCM_TX 0
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3df3497335b..52b005f8fed 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -15,6 +15,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AD1836 if SPI_MASTER
select SND_SOC_AD1938 if SPI_MASTER
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+ select SND_SOC_ADS117X
select SND_SOC_AD73311 if I2C
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
@@ -40,6 +41,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8523 if I2C
select SND_SOC_WM8580 if I2C
select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_WM8727
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
@@ -90,6 +92,9 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
tristate
+
+config SND_SOC_ADS117X
+ tristate
config SND_SOC_AK4104
tristate
@@ -174,6 +179,9 @@ config SND_SOC_WM8580
config SND_SOC_WM8711
tristate
+config SND_SOC_WM8727
+ tristate
+
config SND_SOC_WM8728
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8f519ee9600..dbaecb133ac 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,6 +3,7 @@ snd-soc-ad1836-objs := ad1836.o
snd-soc-ad1938-objs := ad1938.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
+snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
@@ -27,6 +28,7 @@ snd-soc-wm8510-objs := wm8510.o
snd-soc-wm8523-objs := wm8523.o
snd-soc-wm8580-objs := wm8580.o
snd-soc-wm8711-objs := wm8711.o
+snd-soc-wm8727-objs := wm8727.o
snd-soc-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
snd-soc-wm8750-objs := wm8750.o
@@ -57,6 +59,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
@@ -81,6 +84,7 @@ obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
+obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 932299bb5d1..69bd0acc81c 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -117,9 +117,6 @@ static int ac97_soc_probe(struct platform_device *pdev)
if (ret < 0)
goto bus_err;
- ret = snd_soc_init_card(socdev);
- if (ret < 0)
- goto bus_err;
return 0;
bus_err:
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index c48485f2c55..2c18e3d1b71 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -385,19 +385,7 @@ static int ad1836_probe(struct platform_device *pdev)
snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
ARRAY_SIZE(ad1836_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- snd_soc_dapm_new_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
index 34b30efc3cb..5d489186c05 100644
--- a/sound/soc/codecs/ad1938.c
+++ b/sound/soc/codecs/ad1938.c
@@ -592,21 +592,9 @@ static int ad1938_probe(struct platform_device *pdev)
snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
ARRAY_SIZE(ad1938_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- snd_soc_dapm_new_widgets(codec);
ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index d7440a982d2..39c0f7584e6 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -257,11 +257,6 @@ static int ad1980_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
ARRAY_SIZE(ad1980_snd_ac97_controls));
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "ad1980: failed to register card\n");
- goto reset_err;
- }
return 0;
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index e61dac5e7b8..d2fcc601722 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -64,16 +64,8 @@ static int ad73311_soc_probe(struct platform_device *pdev)
goto pcm_err;
}
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "ad73311: failed to register card\n");
- goto register_err;
- }
-
return ret;
-register_err:
- snd_soc_free_pcms(socdev);
pcm_err:
kfree(socdev->card->codec);
socdev->card->codec = NULL;
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
new file mode 100644
index 00000000000..cc96411ca3e
--- /dev/null
+++ b/sound/soc/codecs/ads117x.c
@@ -0,0 +1,123 @@
+/*
+ * ads117x.c -- Driver for ads1174/8 ADC chips
+ *
+ * Copyright 2009 ShotSpotter Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ads117x.h"
+
+#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+struct snd_soc_dai ads117x_dai = {
+/* ADC */
+ .name = "ADS117X ADC",
+ .id = 1,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rates = ADS117X_RATES,
+ .formats = ADS117X_FORMATS,},
+};
+EXPORT_SYMBOL_GPL(ads117x_dai);
+
+static int ads117x_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ socdev->card->codec = codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ codec->name = "ADS117X";
+ codec->owner = THIS_MODULE;
+ codec->dai = &ads117x_dai;
+ codec->num_dai = 1;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "ads117x: failed to create pcms\n");
+ kfree(codec);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ads117x_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ snd_soc_free_pcms(socdev);
+ kfree(codec);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ads117x = {
+ .probe = ads117x_probe,
+ .remove = ads117x_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+
+static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+{
+ ads117x_dai.dev = &pdev->dev;
+ return snd_soc_register_dai(&ads117x_dai);
+}
+
+static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&ads117x_dai);
+ return 0;
+}
+
+static struct platform_driver ads117x_codec_driver = {
+ .driver = {
+ .name = "ads117x",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ads117x_platform_probe,
+ .remove = __devexit_p(ads117x_platform_remove),
+};
+
+static int __init ads117x_init(void)
+{
+ return platform_driver_register(&ads117x_codec_driver);
+}
+module_init(ads117x_init);
+
+static void __exit ads117x_exit(void)
+{
+ platform_driver_unregister(&ads117x_codec_driver);
+}
+module_exit(ads117x_exit);
+
+MODULE_DESCRIPTION("ASoC ads117x driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h
new file mode 100644
index 00000000000..dbcf50ec9bd
--- /dev/null
+++ b/sound/soc/codecs/ads117x.h
@@ -0,0 +1,13 @@
+/*
+ * ads117x.h -- Driver for ads1174/8 ADC chips
+ *
+ * Copyright 2009 ShotSpotter Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ * 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.
+ */
+extern struct snd_soc_dai ads117x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ads117x;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 4d47bc4f742..3a14c6fc4f5 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -313,14 +313,6 @@ static int ak4104_probe(struct platform_device *pdev)
return ret;
}
- /* Register the socdev */
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card\n");
- snd_soc_free_pcms(socdev);
- return ret;
- }
-
return 0;
}
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 0abec0d29a9..ff966567e2b 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -294,7 +294,6 @@ static int ak4535_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -485,17 +484,9 @@ static int ak4535_init(struct snd_soc_device *socdev)
snd_soc_add_controls(codec, ak4535_snd_controls,
ARRAY_SIZE(ak4535_snd_controls));
ak4535_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "ak4535: failed to register card\n");
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index e057c7b578d..b69861d5216 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -442,18 +442,9 @@ static int ak4642_probe(struct platform_device *pdev)
goto pcm_err;
}
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "ak4642: failed to register card\n");
- goto card_err;
- }
-
dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index b61214d1c5d..82fca284d00 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -441,7 +441,6 @@ static int ak4671_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -662,19 +661,10 @@ static int ak4671_probe(struct platform_device *pdev)
ARRAY_SIZE(ak4671_snd_controls));
ak4671_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
-
ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 59bb16d033d..ffe122d1cd7 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -520,6 +520,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
+ SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0),
SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
@@ -598,13 +599,6 @@ static int cs4270_probe(struct platform_device *pdev)
goto error_free_pcms;
}
- /* And finally, register the socdev */
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card\n");
- goto error_free_pcms;
- }
-
return 0;
error_free_pcms:
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 38eac9c866e..e000cdfec1e 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -93,7 +93,6 @@ static int cx20442_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, cx20442_audio_map,
ARRAY_SIZE(cx20442_audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -355,17 +354,6 @@ static int cx20442_codec_probe(struct platform_device *pdev)
cx20442_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 5cda9e6b5a7..2afcd0a8669 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -90,13 +90,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
goto pcm_err;
}
- /* Register Card. */
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "pcm3008: failed to register card\n");
- goto card_err;
- }
-
/* DEM1 DEM0 DE-EMPHASIS_MODE
* Low Low De-emphasis 44.1 kHz ON
* Low High De-emphasis OFF
@@ -136,8 +129,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
gpio_err:
pcm3008_gpio_free(setup);
-card_err:
- snd_soc_free_pcms(socdev);
pcm_err:
kfree(socdev->card->codec);
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index c550750c79c..d2ff1cde688 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -210,7 +210,6 @@ static int ssm2602_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -613,17 +612,9 @@ static int ssm2602_init(struct snd_soc_device *socdev)
snd_soc_add_controls(codec, ssm2602_snd_controls,
ARRAY_SIZE(ssm2602_snd_controls));
ssm2602_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- pr_err("ssm2602: failed to register card\n");
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index befc6488c39..bbc72c2ddfc 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -418,9 +418,6 @@ static int stac9766_codec_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, stac9766_snd_ac97_controls,
ARRAY_SIZE(stac9766_snd_ac97_controls));
- ret = snd_soc_init_card(socdev);
- if (ret < 0)
- goto reset_err;
return 0;
reset_err:
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 0b8dcb5cd72..a091ce77810 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -265,8 +265,8 @@ static const int bosr_usb_divisor_table[] = {
#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15))
static const unsigned short sr_valid_mask[] = {
LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/
- LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/
LOWER_GROUP, /* Usb, bosr - 0*/
+ LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/
UPPER_GROUP, /* Usb, bosr - 1*/
};
/*
@@ -395,7 +395,6 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -707,17 +706,9 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
snd_soc_add_controls(codec, tlv320aic23_snd_controls,
ARRAY_SIZE(tlv320aic23_snd_controls));
tlv320aic23_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "tlv320aic23: failed to register card\n");
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 3387d9e736e..357b609196e 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -356,18 +356,7 @@ static int aic26_probe(struct platform_device *pdev)
ARRAY_SIZE(aic26_snd_controls));
WARN_ON(err < 0);
- /* CODEC is setup, we can register the card now */
- dev_dbg(&pdev->dev, "Registering card\n");
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "aic26: failed to register card\n");
- goto card_err;
- }
return 0;
-
- card_err:
- snd_soc_free_pcms(socdev);
- return ret;
}
static int aic26_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 3395cf945d5..2b4dc2b0b01 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -753,7 +753,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -1405,18 +1404,8 @@ static int aic3x_probe(struct platform_device *pdev)
aic3x_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "aic3x: failed to register card\n");
- goto card_err;
- }
-
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
pcm_err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 3ca8934fc26..2a013e46ae1 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -462,7 +462,6 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -960,16 +959,8 @@ static int dac33_soc_probe(struct platform_device *pdev)
/* power on device */
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card\n");
- goto card_err;
- }
-
return 0;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+
pcm_err:
dac33_hard_power(codec, 0);
return ret;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 5c5a4c0a424..5f1681f6ca7 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -122,9 +122,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
struct twl4030_priv {
struct snd_soc_codec codec;
- unsigned int bypass_state;
unsigned int codec_powered;
- unsigned int codec_muted;
+ unsigned int apll_enabled;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
@@ -215,29 +214,30 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
/* set all audio section registers to reasonable defaults */
for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
- twl4030_write(codec, i, cache[i]);
+ if (i != TWL4030_REG_APLL_CTL)
+ twl4030_write(codec, i, cache[i]);
}
-static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute)
+static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
{
struct twl4030_priv *twl4030 = codec->private_data;
int status;
- if (mute == twl4030->codec_muted)
+ if (enable == twl4030->apll_enabled)
return;
- if (mute)
- /* Disable PLL */
- status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
- else
+ if (enable)
/* Enable PLL */
status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
+ else
+ /* Disable PLL */
+ status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
if (status >= 0)
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
- twl4030->codec_muted = mute;
+ twl4030->apll_enabled = enable;
}
static void twl4030_power_up(struct snd_soc_codec *codec)
@@ -614,6 +614,27 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int vibramux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
+ return 0;
+}
+
+static int apll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ twl4030_apll_enable(w->codec, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ twl4030_apll_enable(w->codec, 0);
+ break;
+ }
+ return 0;
+}
+
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
{
struct snd_soc_device *socdev = codec->socdev;
@@ -725,67 +746,6 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int bypass_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct soc_mixer_control *m =
- (struct soc_mixer_control *)w->kcontrols->private_value;
- struct twl4030_priv *twl4030 = w->codec->private_data;
- unsigned char reg, misc;
-
- reg = twl4030_read_reg_cache(w->codec, m->reg);
-
- /*
- * bypass_state[0:3] - analog HiFi bypass
- * bypass_state[4] - analog voice bypass
- * bypass_state[5] - digital voice bypass
- * bypass_state[6:7] - digital HiFi bypass
- */
- if (m->reg == TWL4030_REG_VSTPGA) {
- /* Voice digital bypass */
- if (reg)
- twl4030->bypass_state |= (1 << 5);
- else
- twl4030->bypass_state &= ~(1 << 5);
- } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
- /* Analog bypass */
- if (reg & (1 << m->shift))
- twl4030->bypass_state |=
- (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
- else
- twl4030->bypass_state &=
- ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
- } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) {
- /* Analog voice bypass */
- if (reg & (1 << m->shift))
- twl4030->bypass_state |= (1 << 4);
- else
- twl4030->bypass_state &= ~(1 << 4);
- } else {
- /* Digital bypass */
- if (reg & (0x7 << m->shift))
- twl4030->bypass_state |= (1 << (m->shift ? 7 : 6));
- else
- twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6));
- }
-
- /* Enable master analog loopback mode if any analog switch is enabled*/
- misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1);
- if (twl4030->bypass_state & 0x1F)
- misc |= TWL4030_FMLOOP_EN;
- else
- misc &= ~TWL4030_FMLOOP_EN;
- twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc);
-
- if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
- if (twl4030->bypass_state)
- twl4030_codec_mute(w->codec, 0);
- else
- twl4030_codec_mute(w->codec, 1);
- }
- return 0;
-}
-
/*
* Some of the gain controls in TWL (mostly those which are associated with
* the outputs) are implemented in an interesting way:
@@ -1193,32 +1153,28 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_NOPM, 0, 0),
/* Analog bypasses */
- SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_abypassr1_control, bypass_event,
- SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_abypassl1_control,
- bypass_event, SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_abypassr2_control,
- bypass_event, SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_abypassl2_control,
- bypass_event, SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_abypassv_control,
- bypass_event, SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassr1_control),
+ SND_SOC_DAPM_SWITCH("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassl1_control),
+ SND_SOC_DAPM_SWITCH("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassr2_control),
+ SND_SOC_DAPM_SWITCH("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassl2_control),
+ SND_SOC_DAPM_SWITCH("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassv_control),
+
+ /* Master analog loopback switch */
+ SND_SOC_DAPM_SUPPLY("FM Loop Enable", TWL4030_REG_MISC_SET_1, 5, 0,
+ NULL, 0),
/* Digital bypasses */
- SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_dbypassl_control, bypass_event,
- SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_dbypassr_control, bypass_event,
- SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_dbypassv_control, bypass_event,
- SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_dbypassl_control),
+ SND_SOC_DAPM_SWITCH("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_dbypassr_control),
+ SND_SOC_DAPM_SWITCH("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_dbypassv_control),
/* Digital mixers, power control for the physical DACs */
SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
@@ -1244,6 +1200,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer",
TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
+ SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
+
/* Output MIXER controls */
/* Earpiece */
SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
@@ -1309,8 +1268,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
0, 0, NULL, 0, handsfreerpga_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
/* Vibra */
- SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
- &twl4030_dapm_vibra_control),
+ SND_SOC_DAPM_MUX_E("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
+ &twl4030_dapm_vibra_control, vibramux_event,
+ SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_vibrapath_control),
@@ -1370,6 +1330,13 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Digital R2 Playback Mixer", NULL, "DAC Right2"},
{"Digital Voice Playback Mixer", NULL, "DAC Voice"},
+ /* Supply for the digital part (APLL) */
+ {"Digital R1 Playback Mixer", NULL, "APLL Enable"},
+ {"Digital L1 Playback Mixer", NULL, "APLL Enable"},
+ {"Digital R2 Playback Mixer", NULL, "APLL Enable"},
+ {"Digital L2 Playback Mixer", NULL, "APLL Enable"},
+ {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
+
{"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"},
{"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"},
{"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"},
@@ -1483,6 +1450,11 @@ static const struct snd_soc_dapm_route intercon[] = {
{"ADC Virtual Left2", NULL, "TX2 Capture Route"},
{"ADC Virtual Right2", NULL, "TX2 Capture Route"},
+ {"ADC Virtual Left1", NULL, "APLL Enable"},
+ {"ADC Virtual Right1", NULL, "APLL Enable"},
+ {"ADC Virtual Left2", NULL, "APLL Enable"},
+ {"ADC Virtual Right2", NULL, "APLL Enable"},
+
/* Analog bypass routes */
{"Right1 Analog Loopback", "Switch", "Analog Right"},
{"Left1 Analog Loopback", "Switch", "Analog Left"},
@@ -1490,6 +1462,13 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Left2 Analog Loopback", "Switch", "Analog Left"},
{"Voice Analog Loopback", "Switch", "Analog Left"},
+ /* Supply for the Analog loopbacks */
+ {"Right1 Analog Loopback", NULL, "FM Loop Enable"},
+ {"Left1 Analog Loopback", NULL, "FM Loop Enable"},
+ {"Right2 Analog Loopback", NULL, "FM Loop Enable"},
+ {"Left2 Analog Loopback", NULL, "FM Loop Enable"},
+ {"Voice Analog Loopback", NULL, "FM Loop Enable"},
+
{"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
{"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
{"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
@@ -1514,32 +1493,20 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
static int twl4030_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct twl4030_priv *twl4030 = codec->private_data;
-
switch (level) {
case SND_SOC_BIAS_ON:
- twl4030_codec_mute(codec, 0);
break;
case SND_SOC_BIAS_PREPARE:
- twl4030_power_up(codec);
- if (twl4030->bypass_state)
- twl4030_codec_mute(codec, 0);
- else
- twl4030_codec_mute(codec, 1);
break;
case SND_SOC_BIAS_STANDBY:
- twl4030_power_up(codec);
- if (twl4030->bypass_state)
- twl4030_codec_mute(codec, 0);
- else
- twl4030_codec_mute(codec, 1);
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ twl4030_power_up(codec);
break;
case SND_SOC_BIAS_OFF:
twl4030_power_down(codec);
@@ -1786,30 +1753,23 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = codec->private_data;
- u8 apll_ctrl;
- apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
- apll_ctrl &= ~TWL4030_APLL_INFREQ;
switch (freq) {
case 19200000:
- apll_ctrl |= TWL4030_APLL_INFREQ_19200KHZ;
- twl4030->sysclk = 19200;
- break;
case 26000000:
- apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ;
- twl4030->sysclk = 26000;
- break;
case 38400000:
- apll_ctrl |= TWL4030_APLL_INFREQ_38400KHZ;
- twl4030->sysclk = 38400;
break;
default:
- printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n",
- freq);
+ dev_err(codec->dev, "Unsupported APLL mclk: %u\n", freq);
return -EINVAL;
}
- twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl);
+ if ((freq / 1000) != twl4030->sysclk) {
+ dev_err(codec->dev,
+ "Mismatch in APLL mclk: %u (configured: %u)\n",
+ freq, twl4030->sysclk * 1000);
+ return -EINVAL;
+ }
return 0;
}
@@ -1907,18 +1867,16 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
- u8 infreq;
+ struct twl4030_priv *twl4030 = codec->private_data;
u8 mode;
/* If the system master clock is not 26MHz, the voice PCM interface is
* not avilable.
*/
- infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL)
- & TWL4030_APLL_INFREQ;
-
- if (infreq != TWL4030_APLL_INFREQ_26000KHZ) {
- printk(KERN_ERR "TWL4030 voice startup: "
- "MCLK is not 26MHz, call set_sysclk() on init\n");
+ if (twl4030->sysclk != 26000) {
+ dev_err(codec->dev, "The board is configured for %u Hz, while"
+ "the Voice interface needs 26MHz APLL mclk\n",
+ twl4030->sysclk * 1000);
return -EINVAL;
}
@@ -1991,22 +1949,19 @@ static int twl4030_voice_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;
- u8 apll_ctrl;
+ struct twl4030_priv *twl4030 = codec->private_data;
- apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
- apll_ctrl &= ~TWL4030_APLL_INFREQ;
- switch (freq) {
- case 26000000:
- apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ;
- break;
- default:
- printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n",
- freq);
+ if (freq != 26000000) {
+ dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice"
+ "interface needs 26MHz APLL mclk\n", freq);
+ return -EINVAL;
+ }
+ if ((freq / 1000) != twl4030->sysclk) {
+ dev_err(codec->dev,
+ "Mismatch in APLL mclk: %u (configured: %u)\n",
+ freq, twl4030->sysclk * 1000);
return -EINVAL;
}
-
- twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl);
-
return 0;
}
@@ -2164,17 +2119,15 @@ static int twl4030_soc_probe(struct platform_device *pdev)
if (setup) {
unsigned char hs_pop;
- if (setup->sysclk)
- twl4030->sysclk = setup->sysclk;
- else
- twl4030->sysclk = 26000;
+ if (setup->sysclk != twl4030->sysclk)
+ dev_warn(&pdev->dev,
+ "Mismatch in APLL mclk: %u (configured: %u)\n",
+ setup->sysclk, twl4030->sysclk);
hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
hs_pop &= ~TWL4030_RAMP_DELAY;
hs_pop |= (setup->ramp_delay_value << 2);
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
- } else {
- twl4030->sysclk = 26000;
}
/* register pcms */
@@ -2188,19 +2141,7 @@ static int twl4030_soc_probe(struct platform_device *pdev)
ARRAY_SIZE(twl4030_snd_controls));
twl4030_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
return 0;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
- return ret;
}
static int twl4030_soc_remove(struct platform_device *pdev)
@@ -2224,10 +2165,8 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
struct twl4030_priv *twl4030;
int ret;
- if (!pdata || !(pdata->audio_mclk == 19200000 ||
- pdata->audio_mclk == 26000000 ||
- pdata->audio_mclk == 38400000)) {
- dev_err(&pdev->dev, "Invalid platform_data\n");
+ if (!pdata) {
+ dev_err(&pdev->dev, "platform_data is missing\n");
return -EINVAL;
}
@@ -2266,7 +2205,9 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
twl4030_codec = codec;
/* Set the defaults, and power up the codec */
+ twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
twl4030_init_chip(codec);
+ codec->bias_level = SND_SOC_BIAS_OFF;
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_register_codec(codec);
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index c33b92edbde..aa40d985138 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -562,17 +562,8 @@ static int uda134x_soc_probe(struct platform_device *pdev)
goto pcm_err;
}
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "UDA134X: failed to register card\n");
- goto card_err;
- }
-
return 0;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
reg_err:
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 92ec0344215..a2763c2e734 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -378,7 +378,6 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -713,17 +712,9 @@ static int uda1380_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, uda1380_snd_controls,
ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 714114b50d1..f82125d9e85 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -800,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec)
return ret;
}
- return snd_soc_dapm_new_widgets(codec);
+ return 0;
}
static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -1501,18 +1501,7 @@ static int wm8350_probe(struct platform_device *pdev)
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
return 0;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
- return ret;
}
static int wm8350_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index bd7eecba20f..b432f4d4a32 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -915,7 +915,6 @@ static int wm8400_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -1400,17 +1399,6 @@ static int wm8400_probe(struct platform_device *pdev)
wm8400_add_controls(codec);
wm8400_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register card\n");
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 5702435af81..265e68c75df 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -219,7 +219,6 @@ static int wm8510_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -604,16 +603,9 @@ static int wm8510_init(struct snd_soc_device *socdev,
snd_soc_add_controls(codec, wm8510_snd_controls,
ARRAY_SIZE(wm8510_snd_controls));
wm8510_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to register card\n");
- goto card_err;
- }
+
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 268cab21c2c..d3a61d7ea0c 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -117,7 +117,6 @@ static int wm8523_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -448,17 +447,9 @@ static int wm8523_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8523_snd_controls,
ARRAY_SIZE(wm8523_snd_controls));
wm8523_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index a09b23e0366..d077df6f5e7 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -315,7 +315,6 @@ static int wm8580_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -800,17 +799,9 @@ static int wm8580_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8580_snd_controls,
ARRAY_SIZE(wm8580_snd_controls));
wm8580_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 54189fbf9e9..24a35603bcf 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -99,7 +99,6 @@ static int wm8711_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -404,17 +403,9 @@ static int wm8711_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8711_snd_controls,
ARRAY_SIZE(wm8711_snd_controls));
wm8711_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
new file mode 100644
index 00000000000..d8ffbd641d7
--- /dev/null
+++ b/sound/soc/codecs/wm8727.c
@@ -0,0 +1,135 @@
+/*
+ * wm8727.c
+ *
+ * Created on: 15-Oct-2009
+ * Author: neil.jones@imgtec.com
+ *
+ * Copyright (C) 2009 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "wm8727.h"
+/*
+ * Note this is a simple chip with no configuration interface, sample rate is
+ * determined automatically by examining the Master clock and Bit clock ratios
+ */
+#define WM8727_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
+
+
+struct snd_soc_dai wm8727_dai = {
+ .name = "WM8727",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM8727_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+};
+EXPORT_SYMBOL_GPL(wm8727_dai);
+
+static int wm8727_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+ mutex_init(&codec->mutex);
+ codec->name = "WM8727";
+ codec->owner = THIS_MODULE;
+ codec->dai = &wm8727_dai;
+ codec->num_dai = 1;
+ socdev->card->codec = codec;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8727: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ return ret;
+
+pcm_err:
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
+ return ret;
+}
+
+static int wm8727_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ if (codec == NULL)
+ return 0;
+ snd_soc_free_pcms(socdev);
+ kfree(codec);
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8727 = {
+ .probe = wm8727_soc_probe,
+ .remove = wm8727_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
+
+
+static __devinit int wm8727_platform_probe(struct platform_device *pdev)
+{
+ wm8727_dai.dev = &pdev->dev;
+ return snd_soc_register_dai(&wm8727_dai);
+}
+
+static int __devexit wm8727_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&wm8727_dai);
+ return 0;
+}
+
+static struct platform_driver wm8727_codec_driver = {
+ .driver = {
+ .name = "wm8727-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wm8727_platform_probe,
+ .remove = __devexit_p(wm8727_platform_remove),
+};
+
+static int __init wm8727_init(void)
+{
+ return platform_driver_register(&wm8727_codec_driver);
+}
+module_init(wm8727_init);
+
+static void __exit wm8727_exit(void)
+{
+ platform_driver_unregister(&wm8727_codec_driver);
+}
+module_exit(wm8727_exit);
+
+MODULE_DESCRIPTION("ASoC wm8727 driver");
+MODULE_AUTHOR("Neil Jones");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
new file mode 100644
index 00000000000..ee19aa71bcd
--- /dev/null
+++ b/sound/soc/codecs/wm8727.h
@@ -0,0 +1,21 @@
+/*
+ * wm8727.h
+ *
+ * Created on: 15-Oct-2009
+ * Author: neil.jones@imgtec.com
+ *
+ * Copyright (C) 2009 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef WM8727_H_
+#define WM8727_H_
+
+extern struct snd_soc_dai wm8727_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8727;
+
+#endif /* WM8727_H_ */
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 16e969a762c..3fb653ba363 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -74,8 +74,6 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
-
return 0;
}
@@ -287,17 +285,9 @@ static int wm8728_init(struct snd_soc_device *socdev,
snd_soc_add_controls(codec, wm8728_snd_controls,
ARRAY_SIZE(wm8728_snd_controls));
wm8728_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8728: failed to register card\n");
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 0e59219a59f..3a497810f93 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -19,6 +19,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -33,9 +34,18 @@
static struct snd_soc_codec *wm8731_codec;
struct snd_soc_codec_device soc_codec_dev_wm8731;
+#define WM8731_NUM_SUPPLIES 4
+static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
+ "AVDD",
+ "HPVDD",
+ "DCVDD",
+ "DBVDD",
+};
+
/* codec private data */
struct wm8731_priv {
struct snd_soc_codec codec;
+ struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk;
};
@@ -149,7 +159,6 @@ static int wm8731_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -422,9 +431,12 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8731_priv *wm8731 = codec->private_data;
snd_soc_write(codec, WM8731_ACTIVE, 0x0);
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
return 0;
}
@@ -432,10 +444,16 @@ static int wm8731_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
- int i;
+ struct wm8731_priv *wm8731 = codec->private_data;
+ int i, ret;
u8 data[2];
u16 *cache = codec->reg_cache;
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
+ if (ret != 0)
+ return ret;
+
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
@@ -444,6 +462,7 @@ static int wm8731_resume(struct platform_device *pdev)
}
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm8731_set_bias_level(codec, codec->suspend_bias_level);
+
return 0;
}
#else
@@ -475,17 +494,9 @@ static int wm8731_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8731_snd_controls,
ARRAY_SIZE(wm8731_snd_controls));
wm8731_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
@@ -512,7 +523,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
static int wm8731_register(struct wm8731_priv *wm8731,
enum snd_soc_control_type control)
{
- int ret;
+ int ret, i;
struct snd_soc_codec *codec = &wm8731->codec;
if (wm8731_codec) {
@@ -543,10 +554,27 @@ static int wm8731_register(struct wm8731_priv *wm8731,
goto err;
}
+ for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
+ wm8731->supplies[i].supply = wm8731_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_regulator_get;
+ }
+
ret = wm8731_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
- goto err;
+ goto err_regulator_enable;
}
wm8731_dai.dev = codec->dev;
@@ -567,7 +595,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- goto err;
+ goto err_regulator_enable;
}
ret = snd_soc_register_dai(&wm8731_dai);
@@ -581,6 +609,10 @@ static int wm8731_register(struct wm8731_priv *wm8731,
err_codec:
snd_soc_unregister_codec(codec);
+err_regulator_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+err_regulator_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
err:
kfree(wm8731);
return ret;
@@ -591,6 +623,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731)
wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
snd_soc_unregister_dai(&wm8731_dai);
snd_soc_unregister_codec(&wm8731->codec);
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+ regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
kfree(wm8731);
wm8731_codec = NULL;
}
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 4ba1e7e93fb..475c67ac781 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -403,7 +403,6 @@ static int wm8750_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -772,16 +771,8 @@ static int wm8750_init(struct snd_soc_device *socdev,
snd_soc_add_controls(codec, wm8750_snd_controls,
ARRAY_SIZE(wm8750_snd_controls));
wm8750_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8750: failed to register card\n");
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 8f7305257d2..d6850dacda2 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -673,7 +673,6 @@ static int wm8753_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -1583,18 +1582,9 @@ static int wm8753_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8753_snd_controls,
ARRAY_SIZE(wm8753_snd_controls));
wm8753_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to register card\n");
- goto card_err;
- }
return 0;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index a0bbb28eed7..ab2c0da1809 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -447,17 +447,8 @@ static int wm8776_probe(struct platform_device *pdev)
ARRAY_SIZE(wm8776_dapm_widgets));
snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
-
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index b48804b5cac..c9438dd62df 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -618,8 +618,6 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
-
return 0;
}
@@ -1353,17 +1351,6 @@ static int wm8900_probe(struct platform_device *pdev)
ARRAY_SIZE(wm8900_snd_controls));
wm8900_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register card\n");
- goto card_err;
- }
-
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 94cdb813041..b8cae175864 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -919,8 +919,6 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(codec);
-
return 0;
}
@@ -1695,17 +1693,8 @@ static int wm8903_probe(struct platform_device *pdev)
ARRAY_SIZE(wm8903_snd_controls));
wm8903_add_widgets(socdev->card->codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "wm8903: failed to register card\n");
- goto card_err;
- }
-
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
return ret;
}
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 8d4fd3c08c0..3d850b97037 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -298,7 +298,6 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec)
ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
if (ret)
goto error_ret;
- ret = snd_soc_dapm_new_widgets(codec);
error_ret:
return ret;
@@ -731,12 +730,6 @@ static int wm8940_probe(struct platform_device *pdev)
if (ret)
goto error_free_pcms;
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto error_free_pcms;
- }
-
return ret;
error_free_pcms:
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index b9b096a8539..d07bcc1e1c6 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -307,7 +307,6 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -713,17 +712,9 @@ static int wm8960_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
wm8960_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index b5c6f2cd5ae..a8007d58813 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -986,19 +986,9 @@ static int wm8961_probe(struct platform_device *pdev)
snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
ARRAY_SIZE(wm8961_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index d66efb0546e..d9540d55fc8 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -338,8 +338,6 @@ static int wm8971_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
-
return 0;
}
@@ -703,16 +701,9 @@ static int wm8971_init(struct snd_soc_device *socdev,
snd_soc_add_controls(codec, wm8971_snd_controls,
ARRAY_SIZE(wm8971_snd_controls));
wm8971_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8971: failed to register card\n");
- goto card_err;
- }
+
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index eff29331235..81c57b5c591 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -276,7 +276,6 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -641,17 +640,9 @@ static int wm8974_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm8974_snd_controls,
ARRAY_SIZE(wm8974_snd_controls));
wm8974_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index d8d8f68b81e..2862e4dced2 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -790,19 +790,9 @@ static int wm8988_probe(struct platform_device *pdev)
snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
ARRAY_SIZE(wm8988_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index f657e9a5fe2..341481e0e83 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -920,7 +920,6 @@ static int wm8990_add_widgets(struct snd_soc_codec *codec)
/* set up the WM8990 audio map */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -1409,16 +1408,9 @@ static int wm8990_init(struct snd_soc_device *socdev)
snd_soc_add_controls(codec, wm8990_snd_controls,
ARRAY_SIZE(wm8990_snd_controls));
wm8990_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8990: failed to register card\n");
- goto card_err;
- }
+
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
return ret;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index dac39771214..5e32f2ed5fc 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1464,19 +1464,8 @@ static int wm8993_probe(struct platform_device *pdev)
wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
wm8993->pdata.lineout2_diff);
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card\n");
- goto card_err;
- }
-
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
err:
return ret;
}
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 4cb6b104b72..c468497314b 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1262,19 +1262,9 @@ static int wm9081_probe(struct platform_device *pdev)
snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets,
ARRAY_SIZE(wm9081_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- dev_err(codec->dev, "failed to register card: %d\n", ret);
- goto card_err;
- }
return ret;
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index e7d2840d9e5..dfffc6c778c 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -205,7 +205,6 @@ static int wm9705_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,
ARRAY_SIZE(wm9705_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -403,16 +402,8 @@ static int wm9705_soc_probe(struct platform_device *pdev)
ARRAY_SIZE(wm9705_snd_ac97_controls));
wm9705_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm9705: failed to register card\n");
- goto reset_err;
- }
-
return 0;
-reset_err:
- snd_soc_free_pcms(socdev);
pcm_err:
snd_soc_free_ac97_codec(codec);
codec_err:
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 1fd4e88f50c..2a087227300 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -436,7 +436,6 @@ static int wm9712_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -695,17 +694,9 @@ static int wm9712_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
ARRAY_SIZE(wm9712_snd_ac97_controls));
wm9712_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm9712: failed to register card\n");
- goto reset_err;
- }
return 0;
-reset_err:
- snd_soc_free_pcms(socdev);
-
pcm_err:
snd_soc_free_ac97_codec(codec);
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index ca3d449ed89..00bac315fb3 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -625,7 +625,6 @@ static int wm9713_add_widgets(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_new_widgets(codec);
return 0;
}
@@ -1247,13 +1246,8 @@ static int wm9713_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
ARRAY_SIZE(wm9713_snd_ac97_controls));
wm9713_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0)
- goto reset_err;
- return 0;
-reset_err:
- snd_soc_free_pcms(socdev);
+ return 0;
pcm_err:
snd_soc_free_ac97_codec(codec);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 2ab809359c0..6362ca05506 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -97,12 +97,24 @@ enum {
DAVINCI_MCBSP_WORD_32,
};
+static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+ [SNDRV_PCM_FORMAT_S8] = 1,
+ [SNDRV_PCM_FORMAT_S16_LE] = 2,
+ [SNDRV_PCM_FORMAT_S32_LE] = 4,
+};
+
+static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+ [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8,
+ [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16,
+ [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32,
+};
+
+static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
+ [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE,
+ [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE,
+};
+
struct davinci_mcbsp_dev {
- /*
- * dma_params must be first because rtd->dai->cpu_dai->private_data
- * is cast to a pointer of an array of struct davinci_pcm_dma_params in
- * davinci_pcm_open.
- */
struct davinci_pcm_dma_params dma_params[2];
void __iomem *base;
#define MOD_DSP_A 0
@@ -110,6 +122,27 @@ struct davinci_mcbsp_dev {
int mode;
u32 pcr;
struct clk *clk;
+ /*
+ * Combining both channels into 1 element will at least double the
+ * amount of time between servicing the dma channel, increase
+ * effiency, and reduce the chance of overrun/underrun. But,
+ * it will result in the left & right channels being swapped.
+ *
+ * If relabeling the left and right channels is not possible,
+ * you may want to let the codec know to swap them back.
+ *
+ * It may allow x10 the amount of time to service dma requests,
+ * if the codec is master and is using an unnecessarily fast bit clock
+ * (ie. tlvaic23b), independent of the sample rate. So, having an
+ * entire frame at once means it can be serviced at the sample rate
+ * instead of the bit clock rate.
+ *
+ * In the now unlikely case that an underrun still
+ * occurs, both the left and right samples will be repeated
+ * so that no pops are heard, and the left and right channels
+ * won't end up being swapped because of the underrun.
+ */
+ unsigned enable_channel_combine:1;
};
static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -349,6 +382,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
int mcbsp_word_length;
unsigned int rcr, xcr, srgr;
u32 spcr;
+ snd_pcm_format_t fmt;
+ unsigned element_cnt = 1;
/* general line settings */
spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
@@ -378,29 +413,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
}
/* Determine xfer data type */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- dma_params->data_type = 1;
- mcbsp_word_length = DAVINCI_MCBSP_WORD_8;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- dma_params->data_type = 2;
- mcbsp_word_length = DAVINCI_MCBSP_WORD_16;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- dma_params->data_type = 4;
- mcbsp_word_length = DAVINCI_MCBSP_WORD_32;
- break;
- default:
+ fmt = params_format(params);
+ if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) {
printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n");
return -EINVAL;
}
- dma_params->acnt = dma_params->data_type;
+ if (params_channels(params) == 2) {
+ element_cnt = 2;
+ if (double_fmt[fmt] && dev->enable_channel_combine) {
+ element_cnt = 1;
+ fmt = double_fmt[fmt];
+ }
+ }
+ dma_params->acnt = dma_params->data_type = data_type[fmt];
dma_params->fifo_level = 0;
-
- rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1);
- xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1);
+ mcbsp_word_length = asp_word_length[fmt];
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -515,7 +545,13 @@ static int davinci_i2s_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_release_region;
}
-
+ if (pdata) {
+ dev->enable_channel_combine = pdata->enable_channel_combine;
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
+ pdata->sram_size_playback;
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
+ pdata->sram_size_capture;
+ }
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = -ENODEV;
@@ -549,6 +585,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
davinci_i2s_dai.private_data = dev;
+ davinci_i2s_dai.dma_data = dev->dma_params;
ret = snd_soc_register_dai(&davinci_i2s_dai);
if (ret != 0)
goto err_free_mem;
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 50ad0519a8f..0a302e1080d 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -904,6 +904,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_data->channel = res->start;
davinci_mcasp_dai[pdata->op_mode].private_data = dev;
+ davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params;
davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 9d179cc88f7..582c9249ef0 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -39,11 +39,6 @@ enum {
};
struct davinci_audio_dev {
- /*
- * dma_params must be first because rtd->dai->cpu_dai->private_data
- * is cast to a pointer of an array of struct davinci_pcm_dma_params in
- * davinci_pcm_open.
- */
struct davinci_pcm_dma_params dma_params[2];
void __iomem *base;
int sample_rate;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index fb10f1d63fd..ad4d7f47a86 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -3,6 +3,7 @@
*
* Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
* Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,10 +24,51 @@
#include <asm/dma.h>
#include <mach/edma.h>
+#include <mach/sram.h>
#include "davinci-pcm.h"
-static struct snd_pcm_hardware davinci_pcm_hardware = {
+#ifdef DEBUG
+static void print_buf_info(int slot, char *name)
+{
+ struct edmacc_param p;
+ if (slot < 0)
+ return;
+ edma_read_slot(slot, &p);
+ printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n",
+ name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
+ printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n",
+ p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
+}
+#else
+static void print_buf_info(int slot, char *name)
+{
+}
+#endif
+
+static struct snd_pcm_hardware pcm_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_KNOT),
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8 * 1024,
+ .periods_min = 16,
+ .periods_max = 255,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware pcm_hardware_capture = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE),
@@ -48,19 +90,63 @@ static struct snd_pcm_hardware davinci_pcm_hardware = {
.fifo_size = 0,
};
+/*
+ * How ping/pong works....
+ *
+ * Playback:
+ * ram_params - copys 2*ping_size from start of SDRAM to iram,
+ * links to ram_link2
+ * ram_link2 - copys rest of SDRAM to iram in ping_size units,
+ * links to ram_link
+ * ram_link - copys entire SDRAM to iram in ping_size uints,
+ * links to self
+ *
+ * asp_params - same as asp_link[0]
+ * asp_link[0] - copys from lower half of iram to asp port
+ * links to asp_link[1], triggers iram copy event on completion
+ * asp_link[1] - copys from upper half of iram to asp port
+ * links to asp_link[0], triggers iram copy event on completion
+ * triggers interrupt only needed to let upper SOC levels update position
+ * in stream on completion
+ *
+ * When playback is started:
+ * ram_params started
+ * asp_params started
+ *
+ * Capture:
+ * ram_params - same as ram_link,
+ * links to ram_link
+ * ram_link - same as playback
+ * links to self
+ *
+ * asp_params - same as playback
+ * asp_link[0] - same as playback
+ * asp_link[1] - same as playback
+ *
+ * When capture is started:
+ * asp_params started
+ */
struct davinci_runtime_data {
spinlock_t lock;
int period; /* current DMA period */
- int master_lch; /* Master DMA channel */
- int slave_lch; /* linked parameter RAM reload slot */
+ int asp_channel; /* Master DMA channel */
+ int asp_link[2]; /* asp parameter link channel, ping/pong */
struct davinci_pcm_dma_params *params; /* DMA params */
+ int ram_channel;
+ int ram_link;
+ int ram_link2;
+ struct edmacc_param asp_params;
+ struct edmacc_param ram_params;
};
+/*
+ * Not used with ping/pong
+ */
static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
{
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
- int lch = prtd->slave_lch;
+ int link = prtd->asp_link[0];
unsigned int period_size;
unsigned int dma_offset;
dma_addr_t dma_pos;
@@ -78,7 +164,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
fifo_level = prtd->params->fifo_level;
pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
- "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size);
+ "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size);
data_type = prtd->params->data_type;
count = period_size / data_type;
@@ -102,16 +188,16 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
}
acnt = prtd->params->acnt;
- edma_set_src(lch, src, INCR, W8BIT);
- edma_set_dest(lch, dst, INCR, W8BIT);
+ edma_set_src(link, src, INCR, W8BIT);
+ edma_set_dest(link, dst, INCR, W8BIT);
- edma_set_src_index(lch, src_bidx, src_cidx);
- edma_set_dest_index(lch, dst_bidx, dst_cidx);
+ edma_set_src_index(link, src_bidx, src_cidx);
+ edma_set_dest_index(link, dst_bidx, dst_cidx);
if (!fifo_level)
- edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC);
+ edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC);
else
- edma_set_transfer_params(lch, acnt, fifo_level, count,
+ edma_set_transfer_params(link, acnt, fifo_level, count,
fifo_level, ABSYNC);
prtd->period++;
@@ -119,46 +205,295 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
prtd->period = 0;
}
-static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data)
+static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
{
struct snd_pcm_substream *substream = data;
struct davinci_runtime_data *prtd = substream->runtime->private_data;
- pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status);
+ print_buf_info(prtd->ram_channel, "i ram_channel");
+ pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
if (unlikely(ch_status != DMA_COMPLETE))
return;
if (snd_pcm_running(substream)) {
+ if (prtd->ram_channel < 0) {
+ /* No ping/pong must fix up link dma data*/
+ spin_lock(&prtd->lock);
+ davinci_pcm_enqueue_dma(substream);
+ spin_unlock(&prtd->lock);
+ }
snd_pcm_period_elapsed(substream);
+ }
+}
+
+static int allocate_sram(struct snd_pcm_substream *substream, unsigned size,
+ struct snd_pcm_hardware *ppcm)
+{
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ struct snd_dma_buffer *iram_dma = NULL;
+ dma_addr_t iram_phys = 0;
+ void *iram_virt = NULL;
+
+ if (buf->private_data || !size)
+ return 0;
+
+ ppcm->period_bytes_max = size;
+ iram_virt = sram_alloc(size, &iram_phys);
+ if (!iram_virt)
+ goto exit1;
+ iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
+ if (!iram_dma)
+ goto exit2;
+ iram_dma->area = iram_virt;
+ iram_dma->addr = iram_phys;
+ memset(iram_dma->area, 0, size);
+ iram_dma->bytes = size;
+ buf->private_data = iram_dma;
+ return 0;
+exit2:
+ if (iram_virt)
+ sram_free(iram_virt, size);
+exit1:
+ return -ENOMEM;
+}
- spin_lock(&prtd->lock);
- davinci_pcm_enqueue_dma(substream);
- spin_unlock(&prtd->lock);
+/*
+ * Only used with ping/pong.
+ * This is called after runtime->dma_addr, period_bytes and data_type are valid
+ */
+static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
+{
+ unsigned short ram_src_cidx, ram_dst_cidx;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct davinci_runtime_data *prtd = runtime->private_data;
+ struct snd_dma_buffer *iram_dma =
+ (struct snd_dma_buffer *)substream->dma_buffer.private_data;
+ struct davinci_pcm_dma_params *params = prtd->params;
+ unsigned int data_type = params->data_type;
+ unsigned int acnt = params->acnt;
+ /* divide by 2 for ping/pong */
+ unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
+ int link = prtd->asp_link[1];
+ unsigned int fifo_level = prtd->params->fifo_level;
+ unsigned int count;
+ if ((data_type == 0) || (data_type > 4)) {
+ printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
+ return -EINVAL;
+ }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
+ ram_src_cidx = ping_size;
+ ram_dst_cidx = -ping_size;
+ edma_set_src(link, asp_src_pong, INCR, W8BIT);
+
+ link = prtd->asp_link[0];
+ edma_set_src_index(link, data_type, data_type * fifo_level);
+ link = prtd->asp_link[1];
+ edma_set_src_index(link, data_type, data_type * fifo_level);
+
+ link = prtd->ram_link;
+ edma_set_src(link, runtime->dma_addr, INCR, W32BIT);
+ } else {
+ dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
+ ram_src_cidx = -ping_size;
+ ram_dst_cidx = ping_size;
+ edma_set_dest(link, asp_dst_pong, INCR, W8BIT);
+
+ link = prtd->asp_link[0];
+ edma_set_dest_index(link, data_type, data_type * fifo_level);
+ link = prtd->asp_link[1];
+ edma_set_dest_index(link, data_type, data_type * fifo_level);
+
+ link = prtd->ram_link;
+ edma_set_dest(link, runtime->dma_addr, INCR, W32BIT);
+ }
+
+ if (!fifo_level) {
+ count = ping_size / data_type;
+ edma_set_transfer_params(prtd->asp_link[0], acnt, count,
+ 1, 0, ASYNC);
+ edma_set_transfer_params(prtd->asp_link[1], acnt, count,
+ 1, 0, ASYNC);
+ } else {
+ count = ping_size / (data_type * fifo_level);
+ edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
+ count, fifo_level, ABSYNC);
+ edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
+ count, fifo_level, ABSYNC);
+ }
+
+ link = prtd->ram_link;
+ edma_set_src_index(link, ping_size, ram_src_cidx);
+ edma_set_dest_index(link, ping_size, ram_dst_cidx);
+ edma_set_transfer_params(link, ping_size, 2,
+ runtime->periods, 2, ASYNC);
+
+ /* init master params */
+ edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
+ edma_read_slot(prtd->ram_link, &prtd->ram_params);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct edmacc_param p_ram;
+ /* Copy entire iram buffer before playback started */
+ prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
+ /* 0 dst_bidx */
+ prtd->ram_params.src_dst_bidx = (ping_size << 1);
+ /* 0 dst_cidx */
+ prtd->ram_params.src_dst_cidx = (ping_size << 1);
+ prtd->ram_params.ccnt = 1;
+
+ /* Skip 1st period */
+ edma_read_slot(prtd->ram_link, &p_ram);
+ p_ram.src += (ping_size << 1);
+ p_ram.ccnt -= 1;
+ edma_write_slot(prtd->ram_link2, &p_ram);
+ /*
+ * When 1st started, ram -> iram dma channel will fill the
+ * entire iram. Then, whenever a ping/pong asp buffer finishes,
+ * 1/2 iram will be filled.
+ */
+ prtd->ram_params.link_bcntrld =
+ EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
}
+ return 0;
+}
+
+/* 1 asp tx or rx channel using 2 parameter channels
+ * 1 ram to/from iram channel using 1 parameter channel
+ *
+ * Playback
+ * ram copy channel kicks off first,
+ * 1st ram copy of entire iram buffer completion kicks off asp channel
+ * asp tcc always kicks off ram copy of 1/2 iram buffer
+ *
+ * Record
+ * asp channel starts, tcc kicks off ram copy
+ */
+static int request_ping_pong(struct snd_pcm_substream *substream,
+ struct davinci_runtime_data *prtd,
+ struct snd_dma_buffer *iram_dma)
+{
+ dma_addr_t asp_src_ping;
+ dma_addr_t asp_dst_ping;
+ int link;
+ struct davinci_pcm_dma_params *params = prtd->params;
+
+ /* Request ram master channel */
+ link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
+ davinci_pcm_dma_irq, substream,
+ EVENTQ_1);
+ if (link < 0)
+ goto exit1;
+
+ /* Request ram link channel */
+ link = prtd->ram_link = edma_alloc_slot(
+ EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
+ if (link < 0)
+ goto exit2;
+
+ link = prtd->asp_link[1] = edma_alloc_slot(
+ EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
+ if (link < 0)
+ goto exit3;
+
+ prtd->ram_link2 = -1;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ link = prtd->ram_link2 = edma_alloc_slot(
+ EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
+ if (link < 0)
+ goto exit4;
+ }
+ /* circle ping-pong buffers */
+ edma_link(prtd->asp_link[0], prtd->asp_link[1]);
+ edma_link(prtd->asp_link[1], prtd->asp_link[0]);
+ /* circle ram buffers */
+ edma_link(prtd->ram_link, prtd->ram_link);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ asp_src_ping = iram_dma->addr;
+ asp_dst_ping = params->dma_addr; /* fifo */
+ } else {
+ asp_src_ping = params->dma_addr; /* fifo */
+ asp_dst_ping = iram_dma->addr;
+ }
+ /* ping */
+ link = prtd->asp_link[0];
+ edma_set_src(link, asp_src_ping, INCR, W16BIT);
+ edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
+ edma_set_src_index(link, 0, 0);
+ edma_set_dest_index(link, 0, 0);
+
+ edma_read_slot(link, &prtd->asp_params);
+ prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
+ prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
+ edma_write_slot(link, &prtd->asp_params);
+
+ /* pong */
+ link = prtd->asp_link[1];
+ edma_set_src(link, asp_src_ping, INCR, W16BIT);
+ edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
+ edma_set_src_index(link, 0, 0);
+ edma_set_dest_index(link, 0, 0);
+
+ edma_read_slot(link, &prtd->asp_params);
+ prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
+ /* interrupt after every pong completion */
+ prtd->asp_params.opt |= TCINTEN | TCCHEN |
+ EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
+ edma_write_slot(link, &prtd->asp_params);
+
+ /* ram */
+ link = prtd->ram_link;
+ edma_set_src(link, iram_dma->addr, INCR, W32BIT);
+ edma_set_dest(link, iram_dma->addr, INCR, W32BIT);
+ pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
+ "for asp:%u %u %u\n", __func__,
+ prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
+ prtd->asp_channel, prtd->asp_link[0],
+ prtd->asp_link[1]);
+ return 0;
+exit4:
+ edma_free_channel(prtd->asp_link[1]);
+ prtd->asp_link[1] = -1;
+exit3:
+ edma_free_channel(prtd->ram_link);
+ prtd->ram_link = -1;
+exit2:
+ edma_free_channel(prtd->ram_channel);
+ prtd->ram_channel = -1;
+exit1:
+ return link;
}
static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
{
+ struct snd_dma_buffer *iram_dma;
struct davinci_runtime_data *prtd = substream->runtime->private_data;
- struct edmacc_param p_ram;
- int ret;
+ struct davinci_pcm_dma_params *params = prtd->params;
+ int link;
- /* Request master DMA channel */
- ret = edma_alloc_channel(prtd->params->channel,
- davinci_pcm_dma_irq, substream,
- EVENTQ_0);
- if (ret < 0)
- return ret;
- prtd->master_lch = ret;
+ if (!params)
+ return -ENODEV;
- /* Request parameter RAM reload slot */
- ret = edma_alloc_slot(EDMA_CTLR(prtd->master_lch), EDMA_SLOT_ANY);
- if (ret < 0) {
- edma_free_channel(prtd->master_lch);
- return ret;
+ /* Request asp master DMA channel */
+ link = prtd->asp_channel = edma_alloc_channel(params->channel,
+ davinci_pcm_dma_irq, substream, EVENTQ_0);
+ if (link < 0)
+ goto exit1;
+
+ /* Request asp link channels */
+ link = prtd->asp_link[0] = edma_alloc_slot(
+ EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
+ if (link < 0)
+ goto exit2;
+
+ iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
+ if (iram_dma) {
+ if (request_ping_pong(substream, prtd, iram_dma) == 0)
+ return 0;
+ printk(KERN_WARNING "%s: dma channel allocation failed,"
+ "not using sram\n", __func__);
}
- prtd->slave_lch = ret;
/* Issue transfer completion IRQ when the channel completes a
* transfer, then always reload from the same slot (by a kind
@@ -169,12 +504,17 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
* the buffer and its length (ccnt) ... use it as a template
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
- edma_read_slot(prtd->slave_lch, &p_ram);
- p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->master_lch));
- p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->slave_lch) << 5;
- edma_write_slot(prtd->slave_lch, &p_ram);
-
+ edma_read_slot(link, &prtd->asp_params);
+ prtd->asp_params.opt |= TCINTEN |
+ EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
+ prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5;
+ edma_write_slot(link, &prtd->asp_params);
return 0;
+exit2:
+ edma_free_channel(prtd->asp_channel);
+ prtd->asp_channel = -1;
+exit1:
+ return link;
}
static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -188,12 +528,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- edma_start(prtd->master_lch);
+ edma_resume(prtd->asp_channel);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- edma_stop(prtd->master_lch);
+ edma_pause(prtd->asp_channel);
break;
default:
ret = -EINVAL;
@@ -208,15 +548,37 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
{
struct davinci_runtime_data *prtd = substream->runtime->private_data;
- struct edmacc_param temp;
+ if (prtd->ram_channel >= 0) {
+ int ret = ping_pong_dma_setup(substream);
+ if (ret < 0)
+ return ret;
+
+ edma_write_slot(prtd->ram_channel, &prtd->ram_params);
+ edma_write_slot(prtd->asp_channel, &prtd->asp_params);
+
+ print_buf_info(prtd->ram_channel, "ram_channel");
+ print_buf_info(prtd->ram_link, "ram_link");
+ print_buf_info(prtd->ram_link2, "ram_link2");
+ print_buf_info(prtd->asp_channel, "asp_channel");
+ print_buf_info(prtd->asp_link[0], "asp_link[0]");
+ print_buf_info(prtd->asp_link[1], "asp_link[1]");
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* copy 1st iram buffer */
+ edma_start(prtd->ram_channel);
+ }
+ edma_start(prtd->asp_channel);
+ return 0;
+ }
prtd->period = 0;
davinci_pcm_enqueue_dma(substream);
/* Copy self-linked parameter RAM entry into master channel */
- edma_read_slot(prtd->slave_lch, &temp);
- edma_write_slot(prtd->master_lch, &temp);
+ edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
+ edma_write_slot(prtd->asp_channel, &prtd->asp_params);
davinci_pcm_enqueue_dma(substream);
+ edma_start(prtd->asp_channel);
return 0;
}
@@ -227,20 +589,53 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct davinci_runtime_data *prtd = runtime->private_data;
unsigned int offset;
- dma_addr_t count;
- dma_addr_t src, dst;
+ int asp_count;
+ dma_addr_t asp_src, asp_dst;
spin_lock(&prtd->lock);
-
- edma_get_position(prtd->master_lch, &src, &dst);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- count = src - runtime->dma_addr;
- else
- count = dst - runtime->dma_addr;
-
+ if (prtd->ram_channel >= 0) {
+ int ram_count;
+ int mod_ram;
+ dma_addr_t ram_src, ram_dst;
+ unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* reading ram before asp should be safe
+ * as long as the asp transfers less than a ping size
+ * of bytes between the 2 reads
+ */
+ edma_get_position(prtd->ram_channel,
+ &ram_src, &ram_dst);
+ edma_get_position(prtd->asp_channel,
+ &asp_src, &asp_dst);
+ asp_count = asp_src - prtd->asp_params.src;
+ ram_count = ram_src - prtd->ram_params.src;
+ mod_ram = ram_count % period_size;
+ mod_ram -= asp_count;
+ if (mod_ram < 0)
+ mod_ram += period_size;
+ else if (mod_ram == 0) {
+ if (snd_pcm_running(substream))
+ mod_ram += period_size;
+ }
+ ram_count -= mod_ram;
+ if (ram_count < 0)
+ ram_count += period_size * runtime->periods;
+ } else {
+ edma_get_position(prtd->ram_channel,
+ &ram_src, &ram_dst);
+ ram_count = ram_dst - prtd->ram_params.dst;
+ }
+ asp_count = ram_count;
+ } else {
+ edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ asp_count = asp_src - runtime->dma_addr;
+ else
+ asp_count = asp_dst - runtime->dma_addr;
+ }
spin_unlock(&prtd->lock);
- offset = bytes_to_frames(runtime, count);
+ offset = bytes_to_frames(runtime, asp_count);
if (offset >= runtime->buffer_size)
offset = 0;
@@ -251,14 +646,19 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct davinci_runtime_data *prtd;
+ struct snd_pcm_hardware *ppcm;
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->private_data;
- struct davinci_pcm_dma_params *params = &pa[substream->stream];
- if (!params)
+ struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data;
+ struct davinci_pcm_dma_params *params;
+ if (!pa)
return -ENODEV;
+ params = &pa[substream->stream];
- snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
+ ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ &pcm_hardware_playback : &pcm_hardware_capture;
+ allocate_sram(substream, params->sram_size, ppcm);
+ snd_soc_set_runtime_hwparams(substream, ppcm);
/* ensure that buffer size is a multiple of period size */
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -271,6 +671,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
spin_lock_init(&prtd->lock);
prtd->params = params;
+ prtd->asp_channel = -1;
+ prtd->asp_link[0] = prtd->asp_link[1] = -1;
+ prtd->ram_channel = -1;
+ prtd->ram_link = -1;
+ prtd->ram_link2 = -1;
runtime->private_data = prtd;
@@ -288,10 +693,29 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct davinci_runtime_data *prtd = runtime->private_data;
- edma_unlink(prtd->slave_lch);
-
- edma_free_slot(prtd->slave_lch);
- edma_free_channel(prtd->master_lch);
+ if (prtd->ram_channel >= 0)
+ edma_stop(prtd->ram_channel);
+ if (prtd->asp_channel >= 0)
+ edma_stop(prtd->asp_channel);
+ if (prtd->asp_link[0] >= 0)
+ edma_unlink(prtd->asp_link[0]);
+ if (prtd->asp_link[1] >= 0)
+ edma_unlink(prtd->asp_link[1]);
+ if (prtd->ram_link >= 0)
+ edma_unlink(prtd->ram_link);
+
+ if (prtd->asp_link[0] >= 0)
+ edma_free_slot(prtd->asp_link[0]);
+ if (prtd->asp_link[1] >= 0)
+ edma_free_slot(prtd->asp_link[1]);
+ if (prtd->asp_channel >= 0)
+ edma_free_channel(prtd->asp_channel);
+ if (prtd->ram_link >= 0)
+ edma_free_slot(prtd->ram_link);
+ if (prtd->ram_link2 >= 0)
+ edma_free_slot(prtd->ram_link2);
+ if (prtd->ram_channel >= 0)
+ edma_free_channel(prtd->ram_channel);
kfree(prtd);
@@ -333,11 +757,11 @@ static struct snd_pcm_ops davinci_pcm_ops = {
.mmap = davinci_pcm_mmap,
};
-static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+ size_t size)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = davinci_pcm_hardware.buffer_bytes_max;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
@@ -362,6 +786,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
int stream;
for (stream = 0; stream < 2; stream++) {
+ struct snd_dma_buffer *iram_dma;
substream = pcm->streams[stream].substream;
if (!substream)
continue;
@@ -373,6 +798,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
dma_free_writecombine(pcm->card->dev, buf->bytes,
buf->area, buf->addr);
buf->area = NULL;
+ iram_dma = (struct snd_dma_buffer *)buf->private_data;
+ if (iram_dma) {
+ sram_free(iram_dma->area, iram_dma->bytes);
+ kfree(iram_dma);
+ }
}
}
@@ -390,14 +820,16 @@ static int davinci_pcm_new(struct snd_card *card,
if (dai->playback.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_PLAYBACK,
+ pcm_hardware_playback.buffer_bytes_max);
if (ret)
return ret;
}
if (dai->capture.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
+ SNDRV_PCM_STREAM_CAPTURE,
+ pcm_hardware_capture.buffer_bytes_max);
if (ret)
return ret;
}
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index c8b0d2baf05..0764944cf10 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -20,6 +20,7 @@ struct davinci_pcm_dma_params {
int channel; /* sync dma channel ID */
unsigned short acnt;
dma_addr_t dma_addr; /* device physical address for DMA */
+ unsigned sram_size;
enum dma_event_q eventq_no; /* event queue number */
unsigned char data_type; /* xfer data type */
unsigned char convert_mono_stereo;
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 6096d22283e..30ed568afb2 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -58,47 +58,15 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
/* Prepare and enqueue the next buffer descriptor */
bd = bcom_prepare_next_buffer(s->bcom_task);
bd->status = s->period_bytes;
- bd->data[0] = s->period_next_pt;
+ bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes);
bcom_submit_next_buffer(s->bcom_task, NULL);
/* Update for next period */
- s->period_next_pt += s->period_bytes;
- if (s->period_next_pt >= s->period_end)
- s->period_next_pt = s->period_start;
-}
-
-static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
-{
- if (s->appl_ptr > s->runtime->control->appl_ptr) {
- /*
- * In this case s->runtime->control->appl_ptr has wrapped around.
- * Play the data to the end of the boundary, then wrap our own
- * appl_ptr back around.
- */
- while (s->appl_ptr < s->runtime->boundary) {
- if (bcom_queue_full(s->bcom_task))
- return;
-
- s->appl_ptr += s->period_size;
-
- psc_dma_bcom_enqueue_next_buffer(s);
- }
- s->appl_ptr -= s->runtime->boundary;
- }
-
- while (s->appl_ptr < s->runtime->control->appl_ptr) {
-
- if (bcom_queue_full(s->bcom_task))
- return;
-
- s->appl_ptr += s->period_size;
-
- psc_dma_bcom_enqueue_next_buffer(s);
- }
+ s->period_next = (s->period_next + 1) % s->runtime->periods;
}
/* Bestcomm DMA irq handler */
-static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
+static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
{
struct psc_dma_stream *s = _psc_dma_stream;
@@ -108,34 +76,8 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
while (bcom_buffer_done(s->bcom_task)) {
bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
- s->period_current_pt += s->period_bytes;
- if (s->period_current_pt >= s->period_end)
- s->period_current_pt = s->period_start;
- }
- psc_dma_bcom_enqueue_tx(s);
- spin_unlock(&s->psc_dma->lock);
-
- /* If the stream is active, then also inform the PCM middle layer
- * of the period finished event. */
- if (s->active)
- snd_pcm_period_elapsed(s->stream);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
-{
- struct psc_dma_stream *s = _psc_dma_stream;
-
- spin_lock(&s->psc_dma->lock);
- /* For each finished period, dequeue the completed period buffer
- * and enqueue a new one in it's place. */
- while (bcom_buffer_done(s->bcom_task)) {
- bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-
- s->period_current_pt += s->period_bytes;
- if (s->period_current_pt >= s->period_end)
- s->period_current_pt = s->period_start;
+ s->period_current = (s->period_current+1) % s->runtime->periods;
+ s->period_count++;
psc_dma_bcom_enqueue_next_buffer(s);
}
@@ -166,54 +108,38 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct psc_dma_stream *s;
+ struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
u16 imr;
unsigned long flags;
int i;
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- s = &psc_dma->capture;
- else
- s = &psc_dma->playback;
-
- dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)"
- " stream_id=%i\n",
- substream, cmd, substream->pstr->stream);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n",
+ substream->pstr->stream, runtime->frame_bits,
+ (int)runtime->period_size, runtime->periods);
s->period_bytes = frames_to_bytes(runtime,
runtime->period_size);
- s->period_start = virt_to_phys(runtime->dma_area);
- s->period_end = s->period_start +
- (s->period_bytes * runtime->periods);
- s->period_next_pt = s->period_start;
- s->period_current_pt = s->period_start;
- s->period_size = runtime->period_size;
+ s->period_next = 0;
+ s->period_current = 0;
s->active = 1;
-
- /* track appl_ptr so that we have a better chance of detecting
- * end of stream and not over running it.
- */
+ s->period_count = 0;
s->runtime = runtime;
- s->appl_ptr = s->runtime->control->appl_ptr -
- (runtime->period_size * runtime->periods);
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
spin_lock_irqsave(&psc_dma->lock, flags);
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
bcom_gen_bd_rx_reset(s->bcom_task);
- for (i = 0; i < runtime->periods; i++)
- if (!bcom_queue_full(s->bcom_task))
- psc_dma_bcom_enqueue_next_buffer(s);
- } else {
+ else
bcom_gen_bd_tx_reset(s->bcom_task);
- psc_dma_bcom_enqueue_tx(s);
- }
+
+ for (i = 0; i < runtime->periods; i++)
+ if (!bcom_queue_full(s->bcom_task))
+ psc_dma_bcom_enqueue_next_buffer(s);
bcom_enable(s->bcom_task);
spin_unlock_irqrestore(&psc_dma->lock, flags);
@@ -223,6 +149,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
break;
case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n",
+ substream->pstr->stream, s->period_count);
s->active = 0;
spin_lock_irqsave(&psc_dma->lock, flags);
@@ -236,7 +164,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
- dev_dbg(psc_dma->dev, "invalid command\n");
+ dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n",
+ substream->pstr->stream, cmd);
return -EINVAL;
}
@@ -343,7 +272,7 @@ psc_dma_pointer(struct snd_pcm_substream *substream)
else
s = &psc_dma->playback;
- count = s->period_current_pt - s->period_start;
+ count = s->period_current * s->period_bytes;
return bytes_to_frames(substream->runtime, count);
}
@@ -532,11 +461,9 @@ int mpc5200_audio_dma_create(struct of_device *op)
rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
"psc-dma-status", psc_dma);
- rc |= request_irq(psc_dma->capture.irq,
- &psc_dma_bcom_irq_rx, IRQF_SHARED,
+ rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-capture", &psc_dma->capture);
- rc |= request_irq(psc_dma->playback.irq,
- &psc_dma_bcom_irq_tx, IRQF_SHARED,
+ rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-playback", &psc_dma->playback);
if (rc) {
ret = -ENODEV;
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index 8d396bb9d9f..22208b373fb 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -13,26 +13,25 @@
* @psc_dma: pointer back to parent psc_dma data structure
* @bcom_task: bestcomm task structure
* @irq: irq number for bestcomm task
- * @period_start: physical address of start of DMA region
* @period_end: physical address of end of DMA region
* @period_next_pt: physical address of next DMA buffer to enqueue
* @period_bytes: size of DMA period in bytes
+ * @ac97_slot_bits: Enable bits for turning on the correct AC97 slot
*/
struct psc_dma_stream {
struct snd_pcm_runtime *runtime;
- snd_pcm_uframes_t appl_ptr;
-
int active;
struct psc_dma *psc_dma;
struct bcom_task *bcom_task;
int irq;
struct snd_pcm_substream *stream;
- dma_addr_t period_start;
- dma_addr_t period_end;
- dma_addr_t period_next_pt;
- dma_addr_t period_current_pt;
+ int period_next;
+ int period_current;
int period_bytes;
- int period_size;
+ int period_count;
+
+ /* AC97 state */
+ u32 ac97_slot_bits;
};
/**
@@ -73,6 +72,15 @@ struct psc_dma {
} stats;
};
+/* Utility for retrieving psc_dma_stream structure from a substream */
+inline struct psc_dma_stream *
+to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
+{
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return &psc_dma->capture;
+ return &psc_dma->playback;
+}
+
int mpc5200_audio_dma_create(struct of_device *op);
int mpc5200_audio_dma_destroy(struct of_device *op);
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index c4ae3e096bb..3dbc7f7cd7b 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -130,6 +130,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
" periods=%i buffer_size=%i buffer_bytes=%i channels=%i"
@@ -140,20 +141,10 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
params_channels(params), params_rate(params),
params_format(params));
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (params_channels(params) == 1)
- psc_dma->slots |= 0x00000100;
- else
- psc_dma->slots |= 0x00000300;
- } else {
- if (params_channels(params) == 1)
- psc_dma->slots |= 0x01000000;
- else
- psc_dma->slots |= 0x03000000;
- }
- out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
-
+ /* Determine the set of enable bits to turn on */
+ s->ac97_slot_bits = (params_channels(params) == 1) ? 0x100 : 0x300;
+ if (substream->pstr->stream != SNDRV_PCM_STREAM_CAPTURE)
+ s->ac97_slot_bits <<= 16;
return 0;
}
@@ -163,6 +154,8 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
{
struct psc_dma *psc_dma = cpu_dai->private_data;
+ dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
+
if (params_channels(params) == 1)
out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
else
@@ -176,14 +169,24 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+ struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ dev_dbg(psc_dma->dev, "AC97 START: stream=%i\n",
+ substream->pstr->stream);
+
+ /* Set the slot enable bits */
+ psc_dma->slots |= s->ac97_slot_bits;
+ out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+ break;
+
case SNDRV_PCM_TRIGGER_STOP:
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- psc_dma->slots &= 0xFFFF0000;
- else
- psc_dma->slots &= 0x0000FFFF;
+ dev_dbg(psc_dma->dev, "AC97 STOP: stream=%i\n",
+ substream->pstr->stream);
+ /* Clear the slot enable bits */
+ psc_dma->slots &= ~(s->ac97_slot_bits);
out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
break;
}
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 2dee9839be8..61952aa6cd5 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -21,7 +21,18 @@ config SND_OMAP_SOC_AMS_DELTA
select SND_OMAP_SOC_MCBSP
select SND_SOC_CX20442
help
- Say Y if you want to add support for SoC audio on Amstrad Delta.
+ Say Y if you want to add support for SoC audio device connected to
+ a handset and a speakerphone found on Amstrad E3 (Delta) videophone.
+
+ Note that in order to get those devices fully supported, you have to
+ build the kernel with standard serial port driver included and
+ configured for at least 4 ports. Then, from userspace, you must load
+ a line discipline #19 on the modem (ttyS3) serial line. The simplest
+ way to achieve this is to install util-linux-ng and use the included
+ ldattach utility. This can be started automatically from udev,
+ a simple rule like this one should do the trick (it does for me):
+ ACTION=="add", KERNEL=="controlC0", \
+ RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
config SND_OMAP_SOC_OSK5912
tristate "SoC Audio support for omap osk5912"
@@ -32,12 +43,13 @@ config SND_OMAP_SOC_OSK5912
Say Y if you want to add support for SoC audio on osk5912.
config SND_OMAP_SOC_OVERO
- tristate "SoC Audio support for Gumstix Overo"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO
+ tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35"
+ depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35)
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
- Say Y if you want to add support for SoC audio on the Gumstix Overo.
+ Say Y if you want to add support for SoC audio on the
+ Gumstix Overo or CompuLab CM-T35
config SND_OMAP_SOC_OMAP2EVM
tristate "SoC Audio support for OMAP2EVM board"
@@ -55,6 +67,15 @@ config SND_OMAP_SOC_OMAP3EVM
help
Say Y if you want to add support for SoC audio on the omap3evm board.
+config SND_OMAP_SOC_AM3517EVM
+ tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
+ depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TLV320AIC23
+ help
+ Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
+ EVM.
+
config SND_OMAP_SOC_SDP3430
tristate "SoC Audio support for Texas Instruments SDP3430"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
@@ -88,3 +109,10 @@ config SND_OMAP_SOC_ZOOM2
help
Say Y if you want to add support for Soc audio on Zoom2 board.
+config SND_OMAP_SOC_IGEP0020
+ tristate "SoC Audio support for IGEP v2"
+ depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y if you want to add support for Soc audio on IGEP v2 board.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 02d69471dcb..d49458a29bb 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -12,10 +12,12 @@ snd-soc-osk5912-objs := osk5912.o
snd-soc-overo-objs := overo.o
snd-soc-omap2evm-objs := omap2evm.o
snd-soc-omap3evm-objs := omap3evm.o
+snd-soc-am3517evm-objs := am3517evm.o
snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o
snd-soc-zoom2-objs := zoom2.o
+snd-soc-igep0020-objs := igep0020.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
@@ -23,7 +25,9 @@ obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
+obj-$(CONFIG_MACH_OMAP3517EVM) += snd-soc-am3517evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
+obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
new file mode 100644
index 00000000000..135901b2ea1
--- /dev/null
+++ b/sound/soc/omap/am3517evm.c
@@ -0,0 +1,202 @@
+/*
+ * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM
+ *
+ * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
+ *
+ * Based on sound/soc/omap/beagle.c by Steve Sakoman
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <plat/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK 12000000
+
+static int am3517evm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ CODEC_CLOCK, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n");
+ return ret;
+ }
+
+ snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops am3517evm_ops = {
+ .hw_params = am3517evm_hw_params,
+};
+
+/* am3517evm machine dapm widgets */
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Line Out", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_MIC("Mic In", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Line Out connected to LLOUT, RLOUT */
+ {"Line Out", NULL, "LOUT"},
+ {"Line Out", NULL, "ROUT"},
+
+ {"LLINEIN", NULL, "Line In"},
+ {"RLINEIN", NULL, "Line In"},
+
+ {"MICIN", NULL, "Mic In"},
+};
+
+static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+{
+ /* Add am3517-evm specific widgets */
+ snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+ ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+ /* Set up davinci-evm specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* always connected */
+ snd_soc_dapm_enable_pin(codec, "Line Out");
+ snd_soc_dapm_enable_pin(codec, "Line In");
+ snd_soc_dapm_enable_pin(codec, "Mic In");
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link am3517evm_dai = {
+ .name = "TLV320AIC23",
+ .stream_name = "AIC23",
+ .cpu_dai = &omap_mcbsp_dai[0],
+ .codec_dai = &tlv320aic23_dai,
+ .init = am3517evm_aic23_init,
+ .ops = &am3517evm_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_am3517evm = {
+ .name = "am3517evm",
+ .platform = &omap_soc_platform,
+ .dai_link = &am3517evm_dai,
+ .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device am3517evm_snd_devdata = {
+ .card = &snd_soc_am3517evm,
+ .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *am3517evm_snd_device;
+
+static int __init am3517evm_soc_init(void)
+{
+ int ret;
+
+ if (!machine_is_omap3517evm()) {
+ pr_err("Not OMAP3517 / AM3517 EVM!\n");
+ return -ENODEV;
+ }
+ pr_info("OMAP3517 / AM3517 EVM SoC init\n");
+
+ am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!am3517evm_snd_device) {
+ printk(KERN_ERR "Platform device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
+ am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
+ *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+
+ ret = platform_device_add(am3517evm_snd_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+
+err1:
+ printk(KERN_ERR "Unable to add platform device\n");
+ platform_device_put(am3517evm_snd_device);
+
+ return ret;
+}
+
+static void __exit am3517evm_soc_exit(void)
+{
+ platform_device_unregister(am3517evm_snd_device);
+}
+
+module_init(am3517evm_soc_init);
+module_exit(am3517evm_soc_exit);
+
+MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
new file mode 100644
index 00000000000..3583c429f9b
--- /dev/null
+++ b/sound/soc/omap/igep0020.c
@@ -0,0 +1,148 @@
+/*
+ * igep0020.c -- SoC audio for IGEP v2
+ *
+ * Based on sound/soc/omap/overo.c by Steve Sakoman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <plat/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+static int igep2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops igep2_ops = {
+ .hw_params = igep2_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link igep2_dai = {
+ .name = "TWL4030",
+ .stream_name = "TWL4030",
+ .cpu_dai = &omap_mcbsp_dai[0],
+ .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+ .ops = &igep2_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_card_igep2 = {
+ .name = "igep2",
+ .platform = &omap_soc_platform,
+ .dai_link = &igep2_dai,
+ .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device igep2_snd_devdata = {
+ .card = &snd_soc_card_igep2,
+ .codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *igep2_snd_device;
+
+static int __init igep2_soc_init(void)
+{
+ int ret;
+
+ if (!machine_is_igep0020()) {
+ pr_debug("Not IGEP v2!\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "IGEP v2 SoC init\n");
+
+ igep2_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!igep2_snd_device) {
+ printk(KERN_ERR "Platform device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
+ igep2_snd_devdata.dev = &igep2_snd_device->dev;
+ *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+ ret = platform_device_add(igep2_snd_device);
+ if (ret)
+ goto err1;
+
+ return 0;
+
+err1:
+ printk(KERN_ERR "Unable to add platform device\n");
+ platform_device_put(igep2_snd_device);
+
+ return ret;
+}
+module_init(igep2_soc_init);
+
+static void __exit igep2_soc_exit(void)
+{
+ platform_device_unregister(igep2_snd_device);
+}
+module_exit(igep2_soc_exit);
+
+MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>");
+MODULE_DESCRIPTION("ALSA SoC IGEP v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 3341f49402c..45be94201c8 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -49,6 +49,8 @@ struct omap_mcbsp_data {
*/
int active;
int configured;
+ unsigned int in_freq;
+ int clk_div;
};
#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -257,7 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
unsigned long port;
- unsigned int format;
+ unsigned int format, div, framesize, master;
if (cpu_class_is_omap1()) {
dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -294,28 +296,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
wpf = channels = params_channels(params);
- switch (channels) {
- case 2:
- if (format == SND_SOC_DAIFMT_I2S) {
- /* Use dual-phase frames */
- regs->rcr2 |= RPHASE;
- regs->xcr2 |= XPHASE;
- /* Set 1 word per (McBSP) frame for phase1 and phase2 */
- wpf--;
- regs->rcr2 |= RFRLEN2(wpf - 1);
- regs->xcr2 |= XFRLEN2(wpf - 1);
- }
- case 1:
- case 4:
- /* Set word per (McBSP) frame for phase1 */
- regs->rcr1 |= RFRLEN1(wpf - 1);
- regs->xcr1 |= XFRLEN1(wpf - 1);
- break;
- default:
- /* Unsupported number of channels */
- return -EINVAL;
+ if (channels == 2 && format == SND_SOC_DAIFMT_I2S) {
+ /* Use dual-phase frames */
+ regs->rcr2 |= RPHASE;
+ regs->xcr2 |= XPHASE;
+ /* Set 1 word per (McBSP) frame for phase1 and phase2 */
+ wpf--;
+ regs->rcr2 |= RFRLEN2(wpf - 1);
+ regs->xcr2 |= XFRLEN2(wpf - 1);
}
+ regs->rcr1 |= RFRLEN1(wpf - 1);
+ regs->xcr1 |= XFRLEN1(wpf - 1);
+
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
/* Set word lengths */
@@ -330,15 +323,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /* In McBSP master modes, FRAME (i.e. sample rate) is generated
+ * by _counting_ BCLKs. Calculate frame size in BCLKs */
+ master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ if (master == SND_SOC_DAIFMT_CBS_CFS) {
+ div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
+ framesize = (mcbsp_data->in_freq / div) / params_rate(params);
+
+ if (framesize < wlen * channels) {
+ printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
+ "channels\n", __func__);
+ return -EINVAL;
+ }
+ } else
+ framesize = wlen * channels;
+
/* Set FS period and length in terms of bit clock periods */
switch (format) {
case SND_SOC_DAIFMT_I2S:
- regs->srgr2 |= FPER(wlen * channels - 1);
- regs->srgr1 |= FWID(wlen - 1);
+ regs->srgr2 |= FPER(framesize - 1);
+ regs->srgr1 |= FWID((framesize >> 1) - 1);
break;
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
- regs->srgr2 |= FPER(wlen * channels - 1);
+ regs->srgr2 |= FPER(framesize - 1);
regs->srgr1 |= FWID(0);
break;
}
@@ -454,6 +462,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
if (div_id != OMAP_MCBSP_CLKGDV)
return -ENODEV;
+ mcbsp_data->clk_div = div;
regs->srgr1 |= CLKGDV(div - 1);
return 0;
@@ -554,6 +563,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
+ mcbsp_data->in_freq = freq;
+
switch (clk_id) {
case OMAP_MCBSP_SYSCLK_CLK:
regs->srgr2 |= CLKSM;
@@ -598,13 +609,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
.id = (link_id), \
.playback = { \
.channels_min = 1, \
- .channels_max = 4, \
+ .channels_max = 16, \
.rates = OMAP_MCBSP_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
.capture = { \
.channels_min = 1, \
- .channels_max = 4, \
+ .channels_max = 16, \
.rates = OMAP_MCBSP_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 9114c263077..f484dcd6340 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -93,10 +93,17 @@ static struct snd_soc_card snd_soc_omap3evm = {
.num_links = 1,
};
+/* twl4030 setup */
+static struct twl4030_setup_data twl4030_setup = {
+ .ramp_delay_value = 4,
+ .sysclk = 26000,
+};
+
/* Audio subsystem */
static struct snd_soc_device omap3evm_snd_devdata = {
.card = &snd_soc_omap3evm,
.codec_dev = &soc_codec_dev_twl4030,
+ .codec_data = &twl4030_setup,
};
static struct platform_device *omap3evm_snd_device;
@@ -144,4 +151,4 @@ module_exit(omap3evm_soc_exit);
MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index ad219aaf7cb..71b2c161158 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -40,9 +40,12 @@
#define PREFIX "ASoC omap3pandora: "
-static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
- struct snd_soc_dai *cpu_dai, unsigned int fmt)
+static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, unsigned int fmt)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
/* Set codec DAI configuration */
@@ -68,8 +71,9 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
}
/* Set McBSP clock to external */
- ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0,
- SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
+ 256 * params_rate(params),
+ SND_SOC_CLOCK_IN);
if (ret < 0) {
pr_err(PREFIX "can't set cpu system clock\n");
return ret;
@@ -87,11 +91,7 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai,
static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
- return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+ return omap3pandora_cmn_hw_params(substream, params,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBS_CFS);
@@ -100,11 +100,7 @@ static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
- return omap3pandora_cmn_hw_params(codec_dai, cpu_dai,
+ return omap3pandora_cmn_hw_params(substream, params,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS);
@@ -134,7 +130,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
* |P| <--- TWL4030 <--------- Line In and MICs
*/
static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
0, 0, NULL, 0, omap3pandora_hp_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -181,6 +177,7 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec)
snd_soc_dapm_nc_pin(codec, "CARKITR");
snd_soc_dapm_nc_pin(codec, "HFL");
snd_soc_dapm_nc_pin(codec, "HFR");
+ snd_soc_dapm_nc_pin(codec, "VIBRA");
ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
ARRAY_SIZE(omap3pandora_out_dapm_widgets));
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index ec4f8fd8b3a..97a4d6308bd 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -107,8 +107,8 @@ static int __init overo_soc_init(void)
{
int ret;
- if (!machine_is_overo()) {
- pr_debug("Not Overo!\n");
+ if (!(machine_is_overo() || machine_is_cm_t35())) {
+ pr_debug("Incomatible machine!\n");
return -ENODEV;
}
printk(KERN_INFO "overo SoC init\n");
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index d7912f1e462..b489f1ae103 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,6 +24,9 @@ config SND_S3C64XX_SOC_I2S
select SND_S3C_I2SV2_SOC
select S3C64XX_DMA
+config SND_S3C_SOC_PCM
+ tristate
+
config SND_S3C2443_SOC_AC97
tristate
select S3C2410_DMA
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 7790406f90b..b744657733d 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,10 +1,11 @@
# S3c24XX Platform Support
-snd-soc-s3c24xx-objs := s3c24xx-pcm.o
+snd-soc-s3c24xx-objs := s3c-dma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
+snd-soc-s3c-pcm-objs := s3c-pcm.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
+obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 93e6c87b739..59dc2c6b56d 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -25,7 +25,7 @@
#include <asm/mach-types.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c2412-i2s.h"
#include "../codecs/wm8750.h"
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 12c71482d25..d00d359a03e 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -24,7 +24,7 @@
#include <sound/soc-dapm.h>
#include "../codecs/ac97.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-ac97.h"
static struct snd_soc_card ln2440sbc;
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 26409a9cef9..dea83d30a5c 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <mach/gta02.h>
#include "../codecs/wm8753.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
static struct snd_soc_card neo1973_gta02;
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 77de6c5127d..0cb4f86f6d1 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -36,7 +36,7 @@
#include "../codecs/wm8753.h"
#include "lm4857.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
/* define the scenarios */
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c-dma.c
index 27cf097c2b1..7725e26d6c9 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -1,5 +1,5 @@
/*
- * s3c24xx-pcm.c -- ALSA Soc Audio Layer
+ * s3c-dma.c -- ALSA Soc Audio Layer
*
* (c) 2006 Wolfson Microelectronics PLC.
* Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
@@ -30,9 +30,9 @@
#include <mach/hardware.h>
#include <mach/dma.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
-static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
+static const struct snd_pcm_hardware s3c_dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -62,23 +62,32 @@ struct s3c24xx_runtime_data {
dma_addr_t dma_start;
dma_addr_t dma_pos;
dma_addr_t dma_end;
- struct s3c24xx_pcm_dma_params *params;
+ struct s3c_dma_params *params;
};
-/* s3c24xx_pcm_enqueue
+/* s3c_dma_enqueue
*
* place a dma buffer onto the queue for the dma system
* to handle.
*/
-static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
+static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
{
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos;
+ unsigned int limit;
int ret;
pr_debug("Entered %s\n", __func__);
- while (prtd->dma_loaded < prtd->dma_limit) {
+ if (s3c_dma_has_circular())
+ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+ else
+ limit = prtd->dma_limit;
+
+ pr_debug("%s: loaded %d, limit %d\n",
+ __func__, prtd->dma_loaded, limit);
+
+ while (prtd->dma_loaded < limit) {
unsigned long len = prtd->dma_period;
pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
@@ -122,21 +131,21 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
snd_pcm_period_elapsed(substream);
spin_lock(&prtd->lock);
- if (prtd->state & ST_RUNNING) {
+ if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
prtd->dma_loaded--;
- s3c24xx_pcm_enqueue(substream);
+ s3c_dma_enqueue(substream);
}
spin_unlock(&prtd->lock);
}
-static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
+static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+ struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;
unsigned long totbytes = params_buffer_bytes(params);
int ret = 0;
@@ -163,6 +172,11 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
printk(KERN_ERR "failed to get dma channel\n");
return ret;
}
+
+ /* use the circular buffering if we have it available. */
+ if (s3c_dma_has_circular())
+ s3c2410_dma_setflags(prtd->params->channel,
+ S3C2410_DMAF_CIRCULAR);
}
s3c2410_dma_set_buffdone_fn(prtd->params->channel,
@@ -184,7 +198,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
+static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
{
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
@@ -201,7 +215,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
+static int s3c_dma_prepare(struct snd_pcm_substream *substream)
{
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
@@ -234,12 +248,12 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
prtd->dma_pos = prtd->dma_start;
/* enqueue dma buffers */
- s3c24xx_pcm_enqueue(substream);
+ s3c_dma_enqueue(substream);
return ret;
}
-static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
@@ -274,7 +288,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
static snd_pcm_uframes_t
-s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
+s3c_dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -309,7 +323,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
return bytes_to_frames(substream->runtime, res);
}
-static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
+static int s3c_dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd;
@@ -317,7 +331,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
+ snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
if (prtd == NULL)
@@ -329,7 +343,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
return 0;
}
-static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
+static int s3c_dma_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -337,14 +351,14 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
if (!prtd)
- pr_debug("s3c24xx_pcm_close called with prtd == NULL\n");
+ pr_debug("s3c_dma_close called with prtd == NULL\n");
kfree(prtd);
return 0;
}
-static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
+static int s3c_dma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -357,23 +371,23 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
}
-static struct snd_pcm_ops s3c24xx_pcm_ops = {
- .open = s3c24xx_pcm_open,
- .close = s3c24xx_pcm_close,
+static struct snd_pcm_ops s3c_dma_ops = {
+ .open = s3c_dma_open,
+ .close = s3c_dma_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = s3c24xx_pcm_hw_params,
- .hw_free = s3c24xx_pcm_hw_free,
- .prepare = s3c24xx_pcm_prepare,
- .trigger = s3c24xx_pcm_trigger,
- .pointer = s3c24xx_pcm_pointer,
- .mmap = s3c24xx_pcm_mmap,
+ .hw_params = s3c_dma_hw_params,
+ .hw_free = s3c_dma_hw_free,
+ .prepare = s3c_dma_prepare,
+ .trigger = s3c_dma_trigger,
+ .pointer = s3c_dma_pointer,
+ .mmap = s3c_dma_mmap,
};
-static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
+ size_t size = s3c_dma_hardware.buffer_bytes_max;
pr_debug("Entered %s\n", __func__);
@@ -388,7 +402,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
return 0;
}
-static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
@@ -411,9 +425,9 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static u64 s3c24xx_pcm_dmamask = DMA_BIT_MASK(32);
+static u64 s3c_dma_mask = DMA_BIT_MASK(32);
-static int s3c24xx_pcm_new(struct snd_card *card,
+static int s3c_dma_new(struct snd_card *card,
struct snd_soc_dai *dai, struct snd_pcm *pcm)
{
int ret = 0;
@@ -421,19 +435,19 @@ static int s3c24xx_pcm_new(struct snd_card *card,
pr_debug("Entered %s\n", __func__);
if (!card->dev->dma_mask)
- card->dev->dma_mask = &s3c24xx_pcm_dmamask;
+ card->dev->dma_mask = &s3c_dma_mask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = 0xffffffff;
if (dai->playback.channels_min) {
- ret = s3c24xx_pcm_preallocate_dma_buffer(pcm,
+ ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
if (dai->capture.channels_min) {
- ret = s3c24xx_pcm_preallocate_dma_buffer(pcm,
+ ret = s3c_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
goto out;
@@ -444,9 +458,9 @@ static int s3c24xx_pcm_new(struct snd_card *card,
struct snd_soc_platform s3c24xx_soc_platform = {
.name = "s3c24xx-audio",
- .pcm_ops = &s3c24xx_pcm_ops,
- .pcm_new = s3c24xx_pcm_new,
- .pcm_free = s3c24xx_pcm_free_dma_buffers,
+ .pcm_ops = &s3c_dma_ops,
+ .pcm_new = s3c_dma_new,
+ .pcm_free = s3c_dma_free_dma_buffers,
};
EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
@@ -463,5 +477,5 @@ static void __exit s3c24xx_soc_platform_exit(void)
module_exit(s3c24xx_soc_platform_exit);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module");
+MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c-dma.h
index 0088c79822e..69bb6bf6fc1 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.h
+++ b/sound/soc/s3c24xx/s3c-dma.h
@@ -1,5 +1,5 @@
/*
- * s3c24xx-pcm.h --
+ * s3c-dma.h --
*
* 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
@@ -9,13 +9,13 @@
* ALSA PCM interface for the Samsung S3C24xx CPU
*/
-#ifndef _S3C24XX_PCM_H
-#define _S3C24XX_PCM_H
+#ifndef _S3C_AUDIO_H
+#define _S3C_AUDIO_H
#define ST_RUNNING (1<<0)
#define ST_OPENED (1<<1)
-struct s3c24xx_pcm_dma_params {
+struct s3c_dma_params {
struct s3c2410_dma_client *client; /* stream identifier */
int channel; /* Channel ID */
dma_addr_t dma_addr;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 28b0ab25509..e994d8374fe 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -35,7 +35,7 @@
#include <mach/dma.h>
#include "s3c-i2s-v2.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#undef S3C_IIS_V2_SUPPORTED
@@ -394,7 +394,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
unsigned long irqs;
int ret = 0;
- int channel = ((struct s3c24xx_pcm_dma_params *)
+ int channel = ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->channel;
pr_debug("Entered %s\n", __func__);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index f66854a77fb..ecf8eaaed1d 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -49,8 +49,8 @@ struct s3c_i2sv2_info {
unsigned char master;
- struct s3c24xx_pcm_dma_params *dma_playback;
- struct s3c24xx_pcm_dma_params *dma_capture;
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
u32 suspend_iismod;
u32 suspend_iiscon;
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
new file mode 100644
index 00000000000..9e61a7c2d9a
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -0,0 +1,552 @@
+/* sound/soc/s3c24xx/s3c-pcm.c
+ *
+ * ALSA SoC Audio Layer - S3C PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar@samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <plat/dma.h>
+
+#include "s3c-dma.h"
+#include "s3c-pcm.h"
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+ .name = "PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+ .name = "PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_out,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+ [0] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+ [1] = {
+ .client = &s3c_pcm_dma_client_in,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_pcm_info s3c_pcm[2];
+
+static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return cpu_dai->private_data;
+}
+
+static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ ctl = readl(regs + S3C_PCM_CTL);
+ ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
+ << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_TXDMA_EN;
+ ctl |= S3C_PCM_CTL_TXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_TXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
+{
+ void __iomem *regs = pcm->regs;
+ u32 ctl, clkctl;
+
+ ctl = readl(regs + S3C_PCM_CTL);
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+ if (on) {
+ ctl |= S3C_PCM_CTL_RXDMA_EN;
+ ctl |= S3C_PCM_CTL_RXFIFO_EN;
+ ctl |= S3C_PCM_CTL_ENABLE;
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ } else {
+ ctl &= ~S3C_PCM_CTL_RXDMA_EN;
+ ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
+
+ if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
+ ctl &= ~S3C_PCM_CTL_ENABLE;
+ if (!pcm->idleclk)
+ clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+ }
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+ writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
+ unsigned long flags;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 1);
+ else
+ s3c_pcm_snd_txctrl(pcm, 1);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c_pcm_snd_rxctrl(pcm, 0);
+ else
+ s3c_pcm_snd_txctrl(pcm, 0);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai = rtd->dai;
+ struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+ void __iomem *regs = pcm->regs;
+ struct clk *clk;
+ int sclk_div, sync_div;
+ unsigned long flags;
+ u32 clkctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->cpu_dai->dma_data = pcm->dma_playback;
+ else
+ dai->cpu_dai->dma_data = pcm->dma_capture;
+
+ /* Strictly check for sample size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ /* Get hold of the PCMSOURCE_CLK */
+ clkctl = readl(regs + S3C_PCM_CLKCTL);
+ if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
+ clk = pcm->pclk;
+ else
+ clk = pcm->cclk;
+
+ /* Set the SCLK divider */
+ sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
+ params_rate(params) / 2 - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+ clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
+ << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+
+ /* Set the SYNC divider */
+ sync_div = pcm->sclk_per_fs - 1;
+
+ clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+ clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
+ << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \
+ SCLK_DIV=%d SYNC_DIV=%d\n",
+ clk_get_rate(clk), pcm->sclk_per_fs,
+ sclk_div, sync_div);
+
+ return 0;
+}
+
+static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ unsigned long flags;
+ int ret = 0;
+ u32 ctl;
+
+ dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+ spin_lock_irqsave(&pcm->lock, flags);
+
+ ctl = readl(regs + S3C_PCM_CTL);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to do, NB_NF by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported clock inversion!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Nothing to do, Master by default */
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported master/slave format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ pcm->idleclk = 1;
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ pcm->idleclk = 0;
+ break;
+ default:
+ dev_err(pcm->dev, "Invalid Clock gating request!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+ ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+ break;
+ default:
+ dev_err(pcm->dev, "Unsupported data format!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ writel(ctl, regs + S3C_PCM_CTL);
+
+exit:
+ spin_unlock_irqrestore(&pcm->lock, flags);
+
+ return ret;
+}
+
+static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct s3c_pcm_info *pcm = to_info(cpu_dai);
+
+ switch (div_id) {
+ case S3C_PCM_SCLK_PER_FS:
+ pcm->sclk_per_fs = div;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct s3c_pcm_info *pcm = to_info(cpu_dai);
+ void __iomem *regs = pcm->regs;
+ u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+ switch (clk_id) {
+ case S3C_PCM_CLKSRC_PCLK:
+ clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+ break;
+
+ case S3C_PCM_CLKSRC_MUX:
+ clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+ if (clk_get_rate(pcm->cclk) != freq)
+ clk_set_rate(pcm->cclk, freq);
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+ .set_sysclk = s3c_pcm_set_sysclk,
+ .set_clkdiv = s3c_pcm_set_clkdiv,
+ .trigger = s3c_pcm_trigger,
+ .hw_params = s3c_pcm_hw_params,
+ .set_fmt = s3c_pcm_set_fmt,
+};
+
+#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
+
+#define S3C_PCM_DECLARE(n) \
+{ \
+ .name = "samsung-pcm", \
+ .id = (n), \
+ .symmetric_rates = 1, \
+ .ops = &s3c_pcm_dai_ops, \
+ .playback = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+ .capture = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = S3C_PCM_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+}
+
+struct snd_soc_dai s3c_pcm_dai[] = {
+ S3C_PCM_DECLARE(0),
+ S3C_PCM_DECLARE(1),
+};
+EXPORT_SYMBOL_GPL(s3c_pcm_dai);
+
+static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm;
+ struct snd_soc_dai *dai;
+ struct resource *mem_res, *dmatx_res, *dmarx_res;
+ struct s3c_audio_pdata *pcm_pdata;
+ int ret;
+
+ /* Check for valid device index */
+ if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
+ dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+ return -EINVAL;
+ }
+
+ pcm_pdata = pdev->dev.platform_data;
+
+ /* Check for availability of necessary resource */
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmatx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
+ return -ENXIO;
+ }
+
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmarx_res) {
+ dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
+ return -ENXIO;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Unable to get register resource\n");
+ return -ENXIO;
+ }
+
+ if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+ return -EINVAL;
+ }
+
+ pcm = &s3c_pcm[pdev->id];
+ pcm->dev = &pdev->dev;
+
+ spin_lock_init(&pcm->lock);
+
+ dai = &s3c_pcm_dai[pdev->id];
+ dai->dev = &pdev->dev;
+
+ /* Default is 128fs */
+ pcm->sclk_per_fs = 128;
+
+ pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+ if (IS_ERR(pcm->cclk)) {
+ dev_err(&pdev->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(pcm->cclk);
+ goto err1;
+ }
+ clk_enable(pcm->cclk);
+
+ /* record our pcm structure for later use in the callbacks */
+ dai->private_data = pcm;
+
+ if (!request_mem_region(mem_res->start,
+ resource_size(mem_res), "samsung-pcm")) {
+ dev_err(&pdev->dev, "Unable to request register region\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ pcm->regs = ioremap(mem_res->start, 0x100);
+ if (pcm->regs == NULL) {
+ dev_err(&pdev->dev, "cannot ioremap registers\n");
+ ret = -ENXIO;
+ goto err3;
+ }
+
+ pcm->pclk = clk_get(&pdev->dev, "pcm");
+ if (IS_ERR(pcm->pclk)) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ ret = -ENOENT;
+ goto err4;
+ }
+ clk_enable(pcm->pclk);
+
+ ret = snd_soc_register_dai(dai);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to get pcm_clock\n");
+ goto err5;
+ }
+
+ s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_RXFIFO;
+ s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+ + S3C_PCM_TXFIFO;
+
+ s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
+ s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+
+ pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
+ pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
+
+ return 0;
+
+err5:
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+err4:
+ iounmap(pcm->regs);
+err3:
+ release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+ clk_disable(pcm->cclk);
+ clk_put(pcm->cclk);
+err1:
+ return ret;
+}
+
+static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
+ struct resource *mem_res;
+
+ iounmap(pcm->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem_res->start, resource_size(mem_res));
+
+ clk_disable(pcm->cclk);
+ clk_disable(pcm->pclk);
+ clk_put(pcm->pclk);
+ clk_put(pcm->cclk);
+
+ return 0;
+}
+
+static struct platform_driver s3c_pcm_driver = {
+ .probe = s3c_pcm_dev_probe,
+ .remove = s3c_pcm_dev_remove,
+ .driver = {
+ .name = "samsung-pcm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c_pcm_init(void)
+{
+ return platform_driver_register(&s3c_pcm_driver);
+}
+module_init(s3c_pcm_init);
+
+static void __exit s3c_pcm_exit(void)
+{
+ platform_driver_unregister(&s3c_pcm_driver);
+}
+module_exit(s3c_pcm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C PCM Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
new file mode 100644
index 00000000000..69ff9971692
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -0,0 +1,123 @@
+/* sound/soc/s3c24xx/s3c-pcm.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __S3C_PCM_H
+#define __S3C_PCM_H __FILE__
+
+/*Register Offsets */
+#define S3C_PCM_CTL (0x00)
+#define S3C_PCM_CLKCTL (0x04)
+#define S3C_PCM_TXFIFO (0x08)
+#define S3C_PCM_RXFIFO (0x0C)
+#define S3C_PCM_IRQCTL (0x10)
+#define S3C_PCM_IRQSTAT (0x14)
+#define S3C_PCM_FIFOSTAT (0x18)
+#define S3C_PCM_CLRINT (0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
+#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
+#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
+#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
+#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
+#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
+#define S3C_PCM_CTL_ENABLE (0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
+#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
+#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
+#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
+#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
+#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
+#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
+#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
+#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
+#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
+#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
+#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
+#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
+#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
+#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
+
+#define S3C_PCM_CLKSRC_PCLK 0
+#define S3C_PCM_CLKSRC_MUX 1
+
+#define S3C_PCM_SCLK_PER_FS 0
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+
+ unsigned int sclk_per_fs;
+
+ /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+ unsigned int idleclk;
+
+ struct clk *pclk;
+ struct clk *cclk;
+
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
+};
+
+#endif /* __S3C_PCM_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index ac5e47b082f..359e59346ba 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -37,7 +37,7 @@
#include <mach/regs-gpio.h>
#include <mach/dma.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c2412-i2s.h"
#define S3C2412_I2S_DEBUG 0
@@ -50,14 +50,14 @@ static struct s3c2410_dma_client s3c2412_dma_client_in = {
.name = "I2S PCM Stereo in"
};
-static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = {
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
.client = &s3c2412_dma_client_out,
.channel = DMACH_I2S_OUT,
.dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD,
.dma_size = 4,
};
-static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
.client = &s3c2412_dma_client_in,
.channel = DMACH_I2S_IN,
.dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD,
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index b25e9f968df..0191e3acb0b 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -35,7 +35,7 @@
#include <asm/dma.h>
#include <mach/dma.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-ac97.h"
struct s3c24xx_ac97_info {
@@ -188,21 +188,21 @@ static struct s3c2410_dma_client s3c2443_dma_client_micin = {
.name = "AC97 Mic Mono in"
};
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = {
.client = &s3c2443_dma_client_out,
.channel = DMACH_PCM_OUT,
.dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
.dma_size = 4,
};
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = {
.client = &s3c2443_dma_client_in,
.channel = DMACH_PCM_IN,
.dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
.dma_size = 4,
};
-static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+static struct s3c_dma_params s3c2443_ac97_mic_mono_in = {
.client = &s3c2443_dma_client_micin,
.channel = DMACH_MIC_IN,
.dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
@@ -290,7 +290,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
{
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int channel = ((struct s3c24xx_pcm_dma_params *)
+ int channel = ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->channel;
ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
@@ -339,7 +339,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
{
u32 ac_glbctrl;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int channel = ((struct s3c24xx_pcm_dma_params *)
+ int channel = ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->channel;
ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index c76b8bb214b..0bc5950b9f0 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -38,7 +38,7 @@
#include <plat/regs-iis.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
static struct s3c2410_dma_client s3c24xx_dma_client_out = {
@@ -49,14 +49,14 @@ static struct s3c2410_dma_client s3c24xx_dma_client_in = {
.name = "I2S PCM Stereo in"
};
-static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = {
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
.client = &s3c24xx_dma_client_out,
.channel = DMACH_I2S_OUT,
.dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
.dma_size = 2,
};
-static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
.client = &s3c24xx_dma_client_in,
.channel = DMACH_I2S_IN,
.dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
@@ -258,12 +258,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
iismod &= ~S3C2410_IISMOD_16BIT;
- ((struct s3c24xx_pcm_dma_params *)
+ ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->dma_size = 1;
break;
case SNDRV_PCM_FORMAT_S16_LE:
iismod |= S3C2410_IISMOD_16BIT;
- ((struct s3c24xx_pcm_dma_params *)
+ ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->dma_size = 2;
break;
default:
@@ -280,7 +280,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int channel = ((struct s3c24xx_pcm_dma_params *)
+ int channel = ((struct s3c_dma_params *)
rtd->dai->cpu_dai->dma_data)->channel;
pr_debug("Entered %s\n", __func__);
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 1966e0d5652..507b2ed5d58 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -21,7 +21,7 @@
#include <plat/audio-simtec.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index 8346bd96eaf..bdf8951af8e 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -18,7 +18,7 @@
#include <plat/audio-simtec.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 25797e09617..185c0acb5ce 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -18,7 +18,7 @@
#include <plat/audio-simtec.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index c215d32d632..052d59659c2 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -24,7 +24,7 @@
#include <plat/regs-iis.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-i2s.h"
#include "../codecs/uda134x.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index b67eed59666..cc7edb5f792 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -35,7 +35,7 @@
#include <mach/map.h>
#include <mach/dma.h>
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
static struct s3c2410_dma_client s3c64xx_dma_client_out = {
@@ -46,7 +46,7 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = {
.name = "I2S PCM Stereo in"
};
-static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
+static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
[0] = {
.channel = DMACH_I2S0_OUT,
.client = &s3c64xx_dma_client_out,
@@ -61,7 +61,7 @@ static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
},
};
-static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
+static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
[0] = {
.channel = DMACH_I2S0_IN,
.client = &s3c64xx_dma_client_in,
@@ -236,6 +236,8 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
goto err;
}
+ clk_enable(i2s->iis_cclk);
+
ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
if (ret)
goto err_clk;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index a2a4f5323c1..12b783b12fc 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -20,7 +20,7 @@
#include <sound/soc-dapm.h>
#include "../codecs/ac97.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c24xx-ac97.h"
static struct snd_soc_card smdk2443;
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index 482aaf10eff..efe4901213a 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -19,7 +19,7 @@
#include <sound/soc-dapm.h>
#include "../codecs/wm8580.h"
-#include "s3c24xx-pcm.h"
+#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
#define S3C64XX_I2S_V4 2
@@ -103,7 +103,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* Set WM8580 to drive MCLK from it's PLLA */
+ /* Set WM8580 to drive MCLK from its PLLA */
ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
WM8580_CLKSRC_PLLA);
if (ret < 0)
@@ -115,8 +115,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* Assuming the CODEC driver evaluates it's rfs too from this call */
- ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
SMDK64XX_WM8580_FREQ, pll_out);
if (ret < 0)
return ret;
@@ -186,9 +185,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
/* Set up PAIFTX audio path */
snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
- /* All enabled by default */
- snd_soc_dapm_enable_pin(codec, "MicIn");
- snd_soc_dapm_enable_pin(codec, "LineIn");
+ /* Enabling the microphone requires the fitting of a 0R
+ * resistor to connect the line from the microphone jack.
+ */
+ snd_soc_dapm_disable_pin(codec, "MicIn");
/* signal a DAPM event */
snd_soc_dapm_sync(codec);
@@ -205,11 +205,6 @@ static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
/* Set up PAIFRX audio path */
snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
- /* All enabled by default */
- snd_soc_dapm_enable_pin(codec, "Front-L/R");
- snd_soc_dapm_enable_pin(codec, "Center/Sub");
- snd_soc_dapm_enable_pin(codec, "Rear-L/R");
-
/* signal a DAPM event */
snd_soc_dapm_sync(codec);
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 83b8028e209..0eb1722f658 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -423,7 +423,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static u64 s6000_pcm_dmamask = DMA_32BIT_MASK;
+static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
static int s6000_pcm_new(struct snd_card *card,
struct snd_soc_dai *dai, struct snd_pcm *pcm)
@@ -435,7 +435,7 @@ static int s6000_pcm_new(struct snd_card *card,
if (!card->dev->dma_mask)
card->dev->dma_mask = &s6000_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
if (params->dma_in) {
s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 9154b4363db..9e697658655 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -23,7 +23,6 @@ config SND_SOC_SH4_SSI
config SND_SOC_SH4_FSI
tristate "SH4 FSI support"
depends on CPU_SUBTYPE_SH7724
- select SH_DMA
help
This option enables FSI sound support
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 44123248b63..e1a3d1a2b4c 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -26,8 +26,6 @@
#include <sound/pcm_params.h>
#include <sound/sh_fsi.h>
#include <asm/atomic.h>
-#include <asm/dma.h>
-#include <asm/dma-sh.h>
#define DO_FMT 0x0000
#define DOFF_CTL 0x0004
@@ -97,7 +95,6 @@ struct fsi_priv {
int fifo_max;
int chan;
- int dma_chan;
int byte_offset;
int period_len;
@@ -308,62 +305,6 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
return residue;
}
-static int fsi_get_residue(struct fsi_priv *fsi, int is_play)
-{
- int residue;
- int width;
- struct snd_pcm_runtime *runtime;
-
- runtime = fsi->substream->runtime;
-
- /* get 1 channel data width */
- width = frames_to_bytes(runtime, 1) / fsi->chan;
-
- if (2 == width)
- residue = fsi_get_fifo_residue(fsi, is_play);
- else
- residue = get_dma_residue(fsi->dma_chan);
-
- return residue;
-}
-
-/************************************************************************
-
-
- basic dma function
-
-
-************************************************************************/
-#define PORTA_DMA 0
-#define PORTB_DMA 1
-
-static int fsi_get_dma_chan(void)
-{
- if (0 != request_dma(PORTA_DMA, "fsia"))
- return -EIO;
-
- if (0 != request_dma(PORTB_DMA, "fsib")) {
- free_dma(PORTA_DMA);
- return -EIO;
- }
-
- master->fsia.dma_chan = PORTA_DMA;
- master->fsib.dma_chan = PORTB_DMA;
-
- return 0;
-}
-
-static void fsi_free_dma_chan(void)
-{
- dma_wait_for_completion(PORTA_DMA);
- dma_wait_for_completion(PORTB_DMA);
- free_dma(PORTA_DMA);
- free_dma(PORTB_DMA);
-
- master->fsia.dma_chan = -1;
- master->fsib.dma_chan = -1;
-}
-
/************************************************************************
@@ -435,44 +376,6 @@ static void fsi_soft_all_reset(void)
mdelay(10);
}
-static void fsi_16data_push(struct fsi_priv *fsi,
- struct snd_pcm_runtime *runtime,
- int send)
-{
- u16 *dma_start;
- u32 snd;
- int i;
-
- /* get dma start position for FSI */
- dma_start = (u16 *)runtime->dma_area;
- dma_start += fsi->byte_offset / 2;
-
- /*
- * soft dma
- * FSI can not use DMA when 16bpp
- */
- for (i = 0; i < send; i++) {
- snd = (u32)dma_start[i];
- fsi_reg_write(fsi, DODT, snd << 8);
- }
-}
-
-static void fsi_32data_push(struct fsi_priv *fsi,
- struct snd_pcm_runtime *runtime,
- int send)
-{
- u32 *dma_start;
-
- /* get dma start position for FSI */
- dma_start = (u32 *)runtime->dma_area;
- dma_start += fsi->byte_offset / 4;
-
- dma_wait_for_completion(fsi->dma_chan);
- dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR));
- dma_write(fsi->dma_chan, (u32)dma_start,
- (u32)(fsi->base + DODT), send * 4);
-}
-
/* playback interrupt */
static int fsi_data_push(struct fsi_priv *fsi)
{
@@ -481,6 +384,8 @@ static int fsi_data_push(struct fsi_priv *fsi)
int send;
int fifo_free;
int width;
+ u8 *start;
+ int i;
if (!fsi ||
!fsi->substream ||
@@ -515,12 +420,22 @@ static int fsi_data_push(struct fsi_priv *fsi)
if (fifo_free < send)
send = fifo_free;
- if (2 == width)
- fsi_16data_push(fsi, runtime, send);
- else if (4 == width)
- fsi_32data_push(fsi, runtime, send);
- else
+ start = runtime->dma_area;
+ start += fsi->byte_offset;
+
+ switch (width) {
+ case 2:
+ for (i = 0; i < send; i++)
+ fsi_reg_write(fsi, DODT,
+ ((u32)*((u16 *)start + i) << 8));
+ break;
+ case 4:
+ for (i = 0; i < send; i++)
+ fsi_reg_write(fsi, DODT, *((u32 *)start + i));
+ break;
+ default:
return -EINVAL;
+ }
fsi->byte_offset += send * width;
@@ -532,6 +447,75 @@ static int fsi_data_push(struct fsi_priv *fsi)
return 0;
}
+static int fsi_data_pop(struct fsi_priv *fsi)
+{
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream = NULL;
+ int free;
+ int fifo_fill;
+ int width;
+ u8 *start;
+ int i;
+
+ if (!fsi ||
+ !fsi->substream ||
+ !fsi->substream->runtime)
+ return -EINVAL;
+
+ runtime = fsi->substream->runtime;
+
+ /* FSI FIFO has limit.
+ * So, this driver can not send periods data at a time
+ */
+ if (fsi->byte_offset >=
+ fsi->period_len * (fsi->periods + 1)) {
+
+ substream = fsi->substream;
+ fsi->periods = (fsi->periods + 1) % runtime->periods;
+
+ if (0 == fsi->periods)
+ fsi->byte_offset = 0;
+ }
+
+ /* get 1 channel data width */
+ width = frames_to_bytes(runtime, 1) / fsi->chan;
+
+ /* get free space for alsa */
+ free = (fsi->buffer_len - fsi->byte_offset) / width;
+
+ /* get recv size */
+ fifo_fill = fsi_get_fifo_residue(fsi, 0);
+
+ if (free < fifo_fill)
+ fifo_fill = free;
+
+ start = runtime->dma_area;
+ start += fsi->byte_offset;
+
+ switch (width) {
+ case 2:
+ for (i = 0; i < fifo_fill; i++)
+ *((u16 *)start + i) =
+ (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+ break;
+ case 4:
+ for (i = 0; i < fifo_fill; i++)
+ *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fsi->byte_offset += fifo_fill * width;
+
+ fsi_irq_enable(fsi, 0);
+
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+
+ return 0;
+}
+
static irqreturn_t fsi_interrupt(int irq, void *data)
{
u32 status = fsi_master_read(SOFT_RST) & ~0x00000010;
@@ -545,6 +529,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
fsi_data_push(&master->fsia);
if (int_st & INT_B_OUT)
fsi_data_push(&master->fsib);
+ if (int_st & INT_A_IN)
+ fsi_data_pop(&master->fsia);
+ if (int_st & INT_B_IN)
+ fsi_data_pop(&master->fsib);
fsi_master_write(INT_ST, 0x0000000);
@@ -664,8 +652,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
}
fsi_reg_write(fsi, reg, data);
- dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n",
- msg, fsi->chan, fsi->dma_chan);
/*
* clear clk reset if master mode
@@ -699,16 +685,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
int ret = 0;
- /* capture not supported */
- if (!is_play)
- return -ENODEV;
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
fsi_stream_push(fsi, substream,
frames_to_bytes(runtime, runtime->buffer_size),
frames_to_bytes(runtime, runtime->period_size));
- ret = fsi_data_push(fsi);
+ ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
break;
case SNDRV_PCM_TRIGGER_STOP:
fsi_irq_disable(fsi, is_play);
@@ -780,10 +762,9 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsi_priv *fsi = fsi_get(substream);
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
long location;
- location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play);
+ location = (fsi->byte_offset - 1);
if (location < 0)
location = 0;
@@ -845,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
.channels_min = 1,
.channels_max = 8,
},
- /* capture not supported */
+ .capture = {
+ .rates = FSI_RATES,
+ .formats = FSI_FMTS,
+ .channels_min = 1,
+ .channels_max = 8,
+ },
.ops = &fsi_dai_ops,
},
{
@@ -857,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = {
.channels_min = 1,
.channels_max = 8,
},
- /* capture not supported */
+ .capture = {
+ .rates = FSI_RATES,
+ .formats = FSI_FMTS,
+ .channels_min = 1,
+ .channels_max = 8,
+ },
.ops = &fsi_dai_ops,
},
};
@@ -912,22 +903,13 @@ static int fsi_probe(struct platform_device *pdev)
master->fsia.base = master->base;
master->fsib.base = master->base + 0x40;
- master->fsia.dma_chan = -1;
- master->fsib.dma_chan = -1;
-
- ret = fsi_get_dma_chan();
- if (ret < 0) {
- dev_err(&pdev->dev, "cannot get dma api\n");
- goto exit_iounmap;
- }
-
/* FSI is based on SPU mstp */
snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id);
master->clk = clk_get(NULL, clk_name);
if (IS_ERR(master->clk)) {
dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name);
ret = -EIO;
- goto exit_free_dma;
+ goto exit_iounmap;
}
fsi_soc_dai[0].dev = &pdev->dev;
@@ -938,7 +920,7 @@ static int fsi_probe(struct platform_device *pdev)
ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
if (ret) {
dev_err(&pdev->dev, "irq request err\n");
- goto exit_free_dma;
+ goto exit_iounmap;
}
ret = snd_soc_register_platform(&fsi_soc_platform);
@@ -951,8 +933,6 @@ static int fsi_probe(struct platform_device *pdev)
exit_free_irq:
free_irq(irq, master);
-exit_free_dma:
- fsi_free_dma_chan();
exit_iounmap:
iounmap(master->base);
exit_kfree:
@@ -969,8 +949,6 @@ static int fsi_remove(struct platform_device *pdev)
clk_put(master->clk);
- fsi_free_dma_chan();
-
free_irq(master->irq, master);
iounmap(master->base);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2d190df9fcc..ef8f28284cb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -37,7 +37,6 @@
#include <sound/initval.h>
static DEFINE_MUTEX(pcm_mutex);
-static DEFINE_MUTEX(io_mutex);
static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
#ifdef CONFIG_DEBUG_FS
@@ -81,6 +80,173 @@ static int run_delayed_work(struct delayed_work *dwork)
return ret;
}
+/* codec register dump */
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
+{
+ int i, step = 1, count = 0;
+
+ if (!codec->reg_cache_size)
+ return 0;
+
+ if (codec->reg_cache_step)
+ step = codec->reg_cache_step;
+
+ count += sprintf(buf, "%s registers\n", codec->name);
+ for (i = 0; i < codec->reg_cache_size; i += step) {
+ if (codec->readable_register && !codec->readable_register(i))
+ continue;
+
+ count += sprintf(buf + count, "%2x: ", i);
+ if (count >= PAGE_SIZE - 1)
+ break;
+
+ if (codec->display_register)
+ count += codec->display_register(codec, buf + count,
+ PAGE_SIZE - count, i);
+ else
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%4x", codec->read(codec, i));
+
+ if (count >= PAGE_SIZE - 1)
+ break;
+
+ count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+ if (count >= PAGE_SIZE - 1)
+ break;
+ }
+
+ /* Truncate count; min() would cause a warning */
+ if (count >= PAGE_SIZE)
+ count = PAGE_SIZE - 1;
+
+ return count;
+}
+static ssize_t codec_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_soc_device *devdata = dev_get_drvdata(dev);
+ return soc_codec_reg_show(devdata->card->codec, buf);
+}
+
+static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
+
+#ifdef CONFIG_DEBUG_FS
+static int codec_reg_open_file(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ struct snd_soc_codec *codec = file->private_data;
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ ret = soc_codec_reg_show(codec, buf);
+ if (ret >= 0)
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t codec_reg_write_file(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ int buf_size;
+ char *start = buf;
+ unsigned long reg, value;
+ int step = 1;
+ struct snd_soc_codec *codec = file->private_data;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ if (codec->reg_cache_step)
+ step = codec->reg_cache_step;
+
+ while (*start == ' ')
+ start++;
+ reg = simple_strtoul(start, &start, 16);
+ if ((reg >= codec->reg_cache_size) || (reg % step))
+ return -EINVAL;
+ while (*start == ' ')
+ start++;
+ if (strict_strtoul(start, 16, &value))
+ return -EINVAL;
+ codec->write(codec, reg, value);
+ return buf_size;
+}
+
+static const struct file_operations codec_reg_fops = {
+ .open = codec_reg_open_file,
+ .read = codec_reg_read_file,
+ .write = codec_reg_write_file,
+};
+
+static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+ char codec_root[128];
+
+ if (codec->dev)
+ snprintf(codec_root, sizeof(codec_root),
+ "%s.%s", codec->name, dev_name(codec->dev));
+ else
+ snprintf(codec_root, sizeof(codec_root),
+ "%s", codec->name);
+
+ codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+ debugfs_root);
+ if (!codec->debugfs_codec_root) {
+ printk(KERN_WARNING
+ "ASoC: Failed to create codec debugfs directory\n");
+ return;
+ }
+
+ codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
+ codec->debugfs_codec_root,
+ codec, &codec_reg_fops);
+ if (!codec->debugfs_reg)
+ printk(KERN_WARNING
+ "ASoC: Failed to create codec register debugfs file\n");
+
+ codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
+ codec->debugfs_codec_root,
+ &codec->pop_time);
+ if (!codec->debugfs_pop_time)
+ printk(KERN_WARNING
+ "Failed to create pop time debugfs file\n");
+
+ codec->debugfs_dapm = debugfs_create_dir("dapm",
+ codec->debugfs_codec_root);
+ if (!codec->debugfs_dapm)
+ printk(KERN_WARNING
+ "Failed to create DAPM debugfs directory\n");
+
+ snd_soc_dapm_debugfs_init(codec);
+}
+
+static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+ debugfs_remove_recursive(codec->debugfs_codec_root);
+}
+
+#else
+
+static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+
+static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
+{
+}
+#endif
+
#ifdef CONFIG_SND_SOC_AC97_BUS
/* unregister ac97 codec */
static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -804,6 +970,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
struct platform_device,
dev);
struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+ struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
struct snd_soc_dai *dai;
int i, found, ret, ac97;
@@ -892,6 +1059,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
if (ret < 0)
goto cpu_dai_err;
}
+ codec = card->codec;
if (platform->probe) {
ret = platform->probe(pdev);
@@ -906,10 +1074,69 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
#endif
+ for (i = 0; i < card->num_links; i++) {
+ if (card->dai_link[i].init) {
+ ret = card->dai_link[i].init(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to init %s\n",
+ card->dai_link[i].stream_name);
+ continue;
+ }
+ }
+ if (card->dai_link[i].codec_dai->ac97_control)
+ ac97 = 1;
+ }
+
+ snprintf(codec->card->shortname, sizeof(codec->card->shortname),
+ "%s", card->name);
+ snprintf(codec->card->longname, sizeof(codec->card->longname),
+ "%s (%s)", card->name, codec->name);
+
+ /* Make sure all DAPM widgets are instantiated */
+ snd_soc_dapm_new_widgets(codec);
+
+ ret = snd_card_register(codec->card);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
+ codec->name);
+ goto card_err;
+ }
+
+ mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ /* Only instantiate AC97 if not already done by the adaptor
+ * for the generic AC97 subsystem.
+ */
+ if (ac97 && strcmp(codec->name, "AC97") != 0) {
+ ret = soc_ac97_dev_register(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: AC97 device register failed\n");
+ snd_card_free(codec->card);
+ mutex_unlock(&codec->mutex);
+ goto card_err;
+ }
+ }
+#endif
+
+ ret = snd_soc_dapm_sys_add(card->socdev->dev);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+
+ ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
+ if (ret < 0)
+ printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
+ soc_init_codec_debugfs(codec);
+ mutex_unlock(&codec->mutex);
+
card->instantiated = 1;
return;
+card_err:
+ if (platform->remove)
+ platform->remove(pdev);
+
platform_err:
if (codec_dev->remove)
codec_dev->remove(pdev);
@@ -1112,173 +1339,6 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
}
EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
-/* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
-{
- int i, step = 1, count = 0;
-
- if (!codec->reg_cache_size)
- return 0;
-
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
-
- count += sprintf(buf, "%s registers\n", codec->name);
- for (i = 0; i < codec->reg_cache_size; i += step) {
- if (codec->readable_register && !codec->readable_register(i))
- continue;
-
- count += sprintf(buf + count, "%2x: ", i);
- if (count >= PAGE_SIZE - 1)
- break;
-
- if (codec->display_register)
- count += codec->display_register(codec, buf + count,
- PAGE_SIZE - count, i);
- else
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%4x", codec->read(codec, i));
-
- if (count >= PAGE_SIZE - 1)
- break;
-
- count += snprintf(buf + count, PAGE_SIZE - count, "\n");
- if (count >= PAGE_SIZE - 1)
- break;
- }
-
- /* Truncate count; min() would cause a warning */
- if (count >= PAGE_SIZE)
- count = PAGE_SIZE - 1;
-
- return count;
-}
-static ssize_t codec_reg_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct snd_soc_device *devdata = dev_get_drvdata(dev);
- return soc_codec_reg_show(devdata->card->codec, buf);
-}
-
-static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
-
-#ifdef CONFIG_DEBUG_FS
-static int codec_reg_open_file(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- ssize_t ret;
- struct snd_soc_codec *codec = file->private_data;
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- ret = soc_codec_reg_show(codec, buf);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
- kfree(buf);
- return ret;
-}
-
-static ssize_t codec_reg_write_file(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- char buf[32];
- int buf_size;
- char *start = buf;
- unsigned long reg, value;
- int step = 1;
- struct snd_soc_codec *codec = file->private_data;
-
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- if (codec->reg_cache_step)
- step = codec->reg_cache_step;
-
- while (*start == ' ')
- start++;
- reg = simple_strtoul(start, &start, 16);
- if ((reg >= codec->reg_cache_size) || (reg % step))
- return -EINVAL;
- while (*start == ' ')
- start++;
- if (strict_strtoul(start, 16, &value))
- return -EINVAL;
- codec->write(codec, reg, value);
- return buf_size;
-}
-
-static const struct file_operations codec_reg_fops = {
- .open = codec_reg_open_file,
- .read = codec_reg_read_file,
- .write = codec_reg_write_file,
-};
-
-static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
- char codec_root[128];
-
- if (codec->dev)
- snprintf(codec_root, sizeof(codec_root),
- "%s.%s", codec->name, dev_name(codec->dev));
- else
- snprintf(codec_root, sizeof(codec_root),
- "%s", codec->name);
-
- codec->debugfs_codec_root = debugfs_create_dir(codec_root,
- debugfs_root);
- if (!codec->debugfs_codec_root) {
- printk(KERN_WARNING
- "ASoC: Failed to create codec debugfs directory\n");
- return;
- }
-
- codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
- codec->debugfs_codec_root,
- codec, &codec_reg_fops);
- if (!codec->debugfs_reg)
- printk(KERN_WARNING
- "ASoC: Failed to create codec register debugfs file\n");
-
- codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
- codec->debugfs_codec_root,
- &codec->pop_time);
- if (!codec->debugfs_pop_time)
- printk(KERN_WARNING
- "Failed to create pop time debugfs file\n");
-
- codec->debugfs_dapm = debugfs_create_dir("dapm",
- codec->debugfs_codec_root);
- if (!codec->debugfs_dapm)
- printk(KERN_WARNING
- "Failed to create DAPM debugfs directory\n");
-
- snd_soc_dapm_debugfs_init(codec);
-}
-
-static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
- debugfs_remove_recursive(codec->debugfs_codec_root);
-}
-
-#else
-
-static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-
-static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-#endif
-
/**
* snd_soc_new_ac97_codec - initailise AC97 device
* @codec: audio codec
@@ -1346,19 +1406,41 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
int change;
unsigned int old, new;
- mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
new = (old & ~mask) | value;
change = old != new;
if (change)
snd_soc_write(codec, reg, new);
- mutex_unlock(&io_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_update_bits);
/**
+ * snd_soc_update_bits_locked - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
+ *
+ * Writes new register value, and takes the codec mutex.
+ *
+ * Returns 1 for change else 0.
+ */
+static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
+ unsigned short reg, unsigned int mask,
+ unsigned int value)
+{
+ int change;
+
+ mutex_lock(&codec->mutex);
+ change = snd_soc_update_bits(codec, reg, mask, value);
+ mutex_unlock(&codec->mutex);
+
+ return change;
+}
+
+/**
* snd_soc_test_bits - test register for change
* @codec: audio codec
* @reg: codec register
@@ -1376,11 +1458,9 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
int change;
unsigned int old, new;
- mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
new = (old & ~mask) | value;
change = old != new;
- mutex_unlock(&io_mutex);
return change;
}
@@ -1427,89 +1507,16 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
mutex_unlock(&codec->mutex);
return ret;
}
- }
-
- mutex_unlock(&codec->mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_init_card - register sound card
- * @socdev: the SoC audio device
- *
- * Register a SoC sound card. Also registers an AC97 device if the
- * codec is AC97 for ad hoc devices.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_init_card(struct snd_soc_device *socdev)
-{
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_codec *codec = card->codec;
- int ret = 0, i, ac97 = 0, err = 0;
-
- for (i = 0; i < card->num_links; i++) {
- if (card->dai_link[i].init) {
- err = card->dai_link[i].init(codec);
- if (err < 0) {
- printk(KERN_ERR "asoc: failed to init %s\n",
- card->dai_link[i].stream_name);
- continue;
- }
- }
if (card->dai_link[i].codec_dai->ac97_control) {
- ac97 = 1;
snd_ac97_dev_add_pdata(codec->ac97,
card->dai_link[i].cpu_dai->ac97_pdata);
}
}
- snprintf(codec->card->shortname, sizeof(codec->card->shortname),
- "%s", card->name);
- snprintf(codec->card->longname, sizeof(codec->card->longname),
- "%s (%s)", card->name, codec->name);
-
- /* Make sure all DAPM widgets are instantiated */
- snd_soc_dapm_new_widgets(codec);
-
- ret = snd_card_register(codec->card);
- if (ret < 0) {
- printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
- codec->name);
- goto out;
- }
-
- mutex_lock(&codec->mutex);
-#ifdef CONFIG_SND_SOC_AC97_BUS
- /* Only instantiate AC97 if not already done by the adaptor
- * for the generic AC97 subsystem.
- */
- if (ac97 && strcmp(codec->name, "AC97") != 0) {
- ret = soc_ac97_dev_register(codec);
- if (ret < 0) {
- printk(KERN_ERR "asoc: AC97 device register failed\n");
- snd_card_free(codec->card);
- mutex_unlock(&codec->mutex);
- goto out;
- }
- }
-#endif
-
- err = snd_soc_dapm_sys_add(socdev->dev);
- if (err < 0)
- printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
- err = device_create_file(socdev->dev, &dev_attr_codec_reg);
- if (err < 0)
- printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
-
- soc_init_codec_debugfs(codec);
mutex_unlock(&codec->mutex);
-
-out:
return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_init_card);
+EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
/**
* snd_soc_free_pcms - free sound card and pcms
@@ -1711,7 +1718,7 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
mask |= (bitmask - 1) << e->shift_r;
}
- return snd_soc_update_bits(codec, e->reg, mask, val);
+ return snd_soc_update_bits_locked(codec, e->reg, mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
@@ -1785,7 +1792,7 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
mask |= e->mask << e->shift_r;
}
- return snd_soc_update_bits(codec, e->reg, mask, val);
+ return snd_soc_update_bits_locked(codec, e->reg, mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
@@ -1946,7 +1953,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
val_mask |= mask << rshift;
val |= val2 << rshift;
}
- return snd_soc_update_bits(codec, reg, val_mask, val);
+ return snd_soc_update_bits_locked(codec, reg, val_mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
@@ -2052,11 +2059,11 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
val = val << shift;
val2 = val2 << shift;
- err = snd_soc_update_bits(codec, reg, val_mask, val);
+ err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
if (err < 0)
return err;
- err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+ err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
return err;
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
@@ -2135,7 +2142,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
val = (ucontrol->value.integer.value[0]+min) & 0xff;
val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
- return snd_soc_update_bits(codec, reg, 0xffff, val);
+ return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index eaadb4b742f..0d294ef7259 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -977,9 +977,19 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
if (!w->power_check)
continue;
- power = w->power_check(w);
- if (power)
- sys_power = 1;
+ /* If we're suspending then pull down all the
+ * power. */
+ switch (event) {
+ case SND_SOC_DAPM_STREAM_SUSPEND:
+ power = 0;
+ break;
+
+ default:
+ power = w->power_check(w);
+ if (power)
+ sys_power = 1;
+ break;
+ }
if (w->power == power)
continue;
@@ -1003,8 +1013,12 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
case SND_SOC_DAPM_STREAM_RESUME:
sys_power = 1;
break;
+ case SND_SOC_DAPM_STREAM_SUSPEND:
+ sys_power = 0;
+ break;
case SND_SOC_DAPM_STREAM_NOP:
sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY;
+ break;
default:
break;
}
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 12124149601..3c07a94c2e3 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -163,6 +163,9 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
else
report = 0;
+ if (gpio->jack_status_check)
+ report = gpio->jack_status_check();
+
snd_soc_jack_report(jack, report, gpio->report);
}
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
new file mode 100644
index 00000000000..b16aaaeb0aa
--- /dev/null
+++ b/sound/soc/soc-utils.c
@@ -0,0 +1,68 @@
+/*
+ * soc-util.c -- ALSA SoC Audio Layer utility functions
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *
+ * 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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
+{
+ return sample_size * channels * tdm_slots;
+}
+EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
+
+int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
+{
+ int sample_size;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ sample_size = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ sample_size = 20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ sample_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S32_BE:
+ sample_size = 32;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return snd_soc_calc_frame_size(sample_size, params_channels(params),
+ 1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size);
+
+int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
+{
+ int ret;
+
+ ret = snd_soc_params_to_frame_size(params);
+
+ if (ret > 0)
+ return ret * params_rate(params);
+ else
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 121af0644fd..86b2c3b92df 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -62,10 +62,14 @@ static void
activate_substream(struct snd_usb_caiaqdev *dev,
struct snd_pcm_substream *sub)
{
+ spin_lock(&dev->spinlock);
+
if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
dev->sub_playback[sub->number] = sub;
else
dev->sub_capture[sub->number] = sub;
+
+ spin_unlock(&dev->spinlock);
}
static void
@@ -269,16 +273,22 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)
{
int index = sub->number;
struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
+ snd_pcm_uframes_t ptr;
+
+ spin_lock(&dev->spinlock);
if (dev->input_panic || dev->output_panic)
- return SNDRV_PCM_POS_XRUN;
+ ptr = SNDRV_PCM_POS_XRUN;
if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return bytes_to_frames(sub->runtime,
+ ptr = bytes_to_frames(sub->runtime,
dev->audio_out_buf_pos[index]);
else
- return bytes_to_frames(sub->runtime,
+ ptr = bytes_to_frames(sub->runtime,
dev->audio_in_buf_pos[index]);
+
+ spin_unlock(&dev->spinlock);
+ return ptr;
}
/* operators for both playback and capture */
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 83e6c1312d4..a3f02dd9744 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -35,7 +35,7 @@
#include "input.h"
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.19");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.20");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, RigKontrol3},"