mirror of https://github.com/hak5/openwrt.git
415 lines
14 KiB
Diff
415 lines
14 KiB
Diff
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
|
|
index 246ac23..874a2c8 100644
|
|
--- a/include/sound/ac97_codec.h
|
|
+++ b/include/sound/ac97_codec.h
|
|
@@ -281,10 +281,12 @@
|
|
/* specific - Analog Devices */
|
|
#define AC97_AD_TEST 0x5a /* test register */
|
|
#define AC97_AD_TEST2 0x5c /* undocumented test register 2 */
|
|
+#define AC97_AD_HPFD_SHIFT 12 /* High Pass Filter Disable */
|
|
#define AC97_AD_CODEC_CFG 0x70 /* codec configuration */
|
|
#define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */
|
|
#define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */
|
|
#define AC97_AD_MISC 0x76 /* Misc Control Bits */
|
|
+#define AC97_AD_VREFD_SHIFT 2 /* V_REFOUT Disable (AD1888) */
|
|
|
|
/* specific - Cirrus Logic */
|
|
#define AC97_CSR_ACMODE 0x5e /* AC Mode Register */
|
|
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
|
|
index bbed644..090e852 100644
|
|
--- a/sound/pci/ac97/ac97_codec.c
|
|
+++ b/sound/pci/ac97/ac97_codec.c
|
|
@@ -49,7 +49,7 @@ module_param(enable_loopback, bool, 0444);
|
|
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
|
|
|
|
#ifdef CONFIG_SND_AC97_POWER_SAVE
|
|
-static int power_save;
|
|
+static int power_save = 1;
|
|
module_param(power_save, bool, 0644);
|
|
MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
|
|
#endif
|
|
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
|
|
index 581ebba..06637f7 100644
|
|
--- a/sound/pci/ac97/ac97_patch.c
|
|
+++ b/sound/pci/ac97/ac97_patch.c
|
|
@@ -1973,8 +1973,9 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = {
|
|
.get = snd_ac97_ad1888_lohpsel_get,
|
|
.put = snd_ac97_ad1888_lohpsel_put
|
|
},
|
|
- AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1),
|
|
- AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1),
|
|
+ AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1),
|
|
+ AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2,
|
|
+ AC97_AD_HPFD_SHIFT, 1, 1),
|
|
AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
|
|
{
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile
|
|
index ad947b4..3866c4d 100644
|
|
--- a/sound/pci/cs5535audio/Makefile
|
|
+++ b/sound/pci/cs5535audio/Makefile
|
|
@@ -8,5 +8,9 @@ ifeq ($(CONFIG_PM),y)
|
|
snd-cs5535audio-objs += cs5535audio_pm.o
|
|
endif
|
|
|
|
+ifdef CONFIG_OLPC
|
|
+snd-cs5535audio-objs += cs5535audio_olpc.o
|
|
+endif
|
|
+
|
|
# Toplevel Module Dependency
|
|
obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
|
|
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
|
|
index b8e75ef..389d9da 100644
|
|
--- a/sound/pci/cs5535audio/cs5535audio.c
|
|
+++ b/sound/pci/cs5535audio/cs5535audio.c
|
|
@@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97,
|
|
return snd_cs5535audio_codec_read(cs5535au, reg);
|
|
}
|
|
|
|
-static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
|
|
+static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
|
|
{
|
|
struct snd_card *card = cs5535au->card;
|
|
struct snd_ac97_bus *pbus;
|
|
@@ -160,10 +160,14 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
|
|
return err;
|
|
|
|
memset(&ac97, 0, sizeof(ac97));
|
|
- ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
|
|
+ ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
|
|
+ | AC97_SCAP_POWER_SAVE;
|
|
ac97.private_data = cs5535au;
|
|
ac97.pci = cs5535au->pci;
|
|
|
|
+ /* olpc_prequirks is dummied out if not olpc */
|
|
+ olpc_prequirks(card, &ac97);
|
|
+
|
|
if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
|
|
snd_printk(KERN_ERR "mixer failed\n");
|
|
return err;
|
|
@@ -171,6 +175,12 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
|
|
|
|
snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
|
|
|
|
+ /* olpc_quirks is dummied out if not olpc */
|
|
+ if (( err = olpc_quirks(card, cs5535au->ac97)) < 0) {
|
|
+ snd_printk(KERN_ERR "olpc quirks failed\n");
|
|
+ return err;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -206,7 +216,6 @@ static void process_bm1_irq(struct cs5535audio *cs5535au)
|
|
static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
|
|
{
|
|
u16 acc_irq_stat;
|
|
- u8 bm_stat;
|
|
unsigned char count;
|
|
struct cs5535audio *cs5535au = dev_id;
|
|
|
|
@@ -217,7 +226,7 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
|
|
|
|
if (!acc_irq_stat)
|
|
return IRQ_NONE;
|
|
- for (count = 0; count < 10; count++) {
|
|
+ for (count = 0; count < 4; count++) {
|
|
if (acc_irq_stat & (1 << count)) {
|
|
switch (count) {
|
|
case IRQ_STS:
|
|
@@ -232,26 +241,9 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
|
|
case BM1_IRQ_STS:
|
|
process_bm1_irq(cs5535au);
|
|
break;
|
|
- case BM2_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS);
|
|
- break;
|
|
- case BM3_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS);
|
|
- break;
|
|
- case BM4_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS);
|
|
- break;
|
|
- case BM5_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS);
|
|
- break;
|
|
- case BM6_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS);
|
|
- break;
|
|
- case BM7_IRQ_STS:
|
|
- bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS);
|
|
- break;
|
|
default:
|
|
- snd_printk(KERN_ERR "Unexpected irq src\n");
|
|
+ snd_printk(KERN_ERR "Unexpected irq src: "
|
|
+ "0x%x\n", acc_irq_stat);
|
|
break;
|
|
}
|
|
}
|
|
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h
|
|
index 4fd1f31..ff82f10 100644
|
|
--- a/sound/pci/cs5535audio/cs5535audio.h
|
|
+++ b/sound/pci/cs5535audio/cs5535audio.h
|
|
@@ -16,57 +16,28 @@
|
|
#define ACC_IRQ_STATUS 0x12
|
|
#define ACC_BM0_CMD 0x20
|
|
#define ACC_BM1_CMD 0x28
|
|
-#define ACC_BM2_CMD 0x30
|
|
-#define ACC_BM3_CMD 0x38
|
|
-#define ACC_BM4_CMD 0x40
|
|
-#define ACC_BM5_CMD 0x48
|
|
-#define ACC_BM6_CMD 0x50
|
|
-#define ACC_BM7_CMD 0x58
|
|
#define ACC_BM0_PRD 0x24
|
|
#define ACC_BM1_PRD 0x2C
|
|
-#define ACC_BM2_PRD 0x34
|
|
-#define ACC_BM3_PRD 0x3C
|
|
-#define ACC_BM4_PRD 0x44
|
|
-#define ACC_BM5_PRD 0x4C
|
|
-#define ACC_BM6_PRD 0x54
|
|
-#define ACC_BM7_PRD 0x5C
|
|
#define ACC_BM0_STATUS 0x21
|
|
#define ACC_BM1_STATUS 0x29
|
|
-#define ACC_BM2_STATUS 0x31
|
|
-#define ACC_BM3_STATUS 0x39
|
|
-#define ACC_BM4_STATUS 0x41
|
|
-#define ACC_BM5_STATUS 0x49
|
|
-#define ACC_BM6_STATUS 0x51
|
|
-#define ACC_BM7_STATUS 0x59
|
|
#define ACC_BM0_PNTR 0x60
|
|
#define ACC_BM1_PNTR 0x64
|
|
-#define ACC_BM2_PNTR 0x68
|
|
-#define ACC_BM3_PNTR 0x6C
|
|
-#define ACC_BM4_PNTR 0x70
|
|
-#define ACC_BM5_PNTR 0x74
|
|
-#define ACC_BM6_PNTR 0x78
|
|
-#define ACC_BM7_PNTR 0x7C
|
|
+
|
|
/* acc_codec bar0 reg bits */
|
|
/* ACC_IRQ_STATUS */
|
|
#define IRQ_STS 0
|
|
#define WU_IRQ_STS 1
|
|
#define BM0_IRQ_STS 2
|
|
#define BM1_IRQ_STS 3
|
|
-#define BM2_IRQ_STS 4
|
|
-#define BM3_IRQ_STS 5
|
|
-#define BM4_IRQ_STS 6
|
|
-#define BM5_IRQ_STS 7
|
|
-#define BM6_IRQ_STS 8
|
|
-#define BM7_IRQ_STS 9
|
|
/* ACC_BMX_STATUS */
|
|
#define EOP (1<<0)
|
|
#define BM_EOP_ERR (1<<1)
|
|
/* ACC_BMX_CTL */
|
|
-#define BM_CTL_EN 0x00000001
|
|
-#define BM_CTL_PAUSE 0x00000011
|
|
-#define BM_CTL_DIS 0x00000000
|
|
-#define BM_CTL_BYTE_ORD_LE 0x00000000
|
|
-#define BM_CTL_BYTE_ORD_BE 0x00000100
|
|
+#define BM_CTL_EN 0x01
|
|
+#define BM_CTL_PAUSE 0x03
|
|
+#define BM_CTL_DIS 0x00
|
|
+#define BM_CTL_BYTE_ORD_LE 0x00
|
|
+#define BM_CTL_BYTE_ORD_BE 0x04
|
|
/* cs5535 specific ac97 codec register defines */
|
|
#define CMD_MASK 0xFF00FFFF
|
|
#define CMD_NEW 0x00010000
|
|
@@ -106,8 +77,8 @@ struct cs5535audio_dma {
|
|
struct snd_pcm_substream *substream;
|
|
unsigned int buf_addr, buf_bytes;
|
|
unsigned int period_bytes, periods;
|
|
- int suspended;
|
|
u32 saved_prd;
|
|
+ int pcm_open_flag;
|
|
};
|
|
|
|
struct cs5535audio {
|
|
@@ -123,8 +94,21 @@ struct cs5535audio {
|
|
struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
|
|
};
|
|
|
|
+#ifdef CONFIG_PM
|
|
int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
|
|
int snd_cs5535audio_resume(struct pci_dev *pci);
|
|
+#endif
|
|
+
|
|
+#ifdef CONFIG_OLPC
|
|
+void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) __devinit;
|
|
+int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) __devinit;
|
|
+int olpc_ai_enable(struct snd_ac97 *ac97, u8 val);
|
|
+#else
|
|
+#define olpc_prequirks(arg,arg2) do {} while (0)
|
|
+#define olpc_quirks(arg,arg2) (0)
|
|
+#define olpc_ai_enable(a, v) (0)
|
|
+#endif
|
|
+
|
|
int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
|
|
|
|
#endif /* __SOUND_CS5535AUDIO_H */
|
|
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
|
|
index 5450a9e..d23f8ea 100644
|
|
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
|
|
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
|
|
@@ -164,6 +164,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
|
|
jmpprd_addr = cpu_to_le32(lastdesc->addr +
|
|
(sizeof(struct cs5535audio_dma_desc)*periods));
|
|
|
|
+ dma->substream = substream;
|
|
dma->period_bytes = period_bytes;
|
|
dma->periods = periods;
|
|
spin_lock_irq(&cs5535au->reg_lock);
|
|
@@ -241,6 +242,7 @@ static void cs5535audio_clear_dma_packets(struct cs5535audio *cs5535au,
|
|
{
|
|
snd_dma_free_pages(&dma->desc_buf);
|
|
dma->desc_buf.area = NULL;
|
|
+ dma->substream = NULL;
|
|
}
|
|
|
|
static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream,
|
|
@@ -260,6 +262,9 @@ static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream,
|
|
err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
|
|
params_periods(hw_params),
|
|
params_period_bytes(hw_params));
|
|
+ if (!err)
|
|
+ dma->pcm_open_flag = 1;
|
|
+
|
|
return err;
|
|
}
|
|
|
|
@@ -268,6 +273,15 @@ static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream)
|
|
struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
|
|
struct cs5535audio_dma *dma = substream->runtime->private_data;
|
|
|
|
+ if (dma->pcm_open_flag) {
|
|
+ if (substream == cs5535au->playback_substream)
|
|
+ snd_ac97_update_power(cs5535au->ac97,
|
|
+ AC97_PCM_FRONT_DAC_RATE, 0);
|
|
+ else
|
|
+ snd_ac97_update_power(cs5535au->ac97,
|
|
+ AC97_PCM_LR_ADC_RATE, 0);
|
|
+ dma->pcm_open_flag = 0;
|
|
+ }
|
|
cs5535audio_clear_dma_packets(cs5535au, dma, substream);
|
|
return snd_pcm_lib_free_pages(substream);
|
|
}
|
|
@@ -298,14 +312,12 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
break;
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
dma->ops->enable_dma(cs5535au);
|
|
- dma->suspended = 0;
|
|
break;
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
dma->ops->disable_dma(cs5535au);
|
|
break;
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
dma->ops->disable_dma(cs5535au);
|
|
- dma->suspended = 1;
|
|
break;
|
|
default:
|
|
snd_printk(KERN_ERR "unhandled trigger\n");
|
|
@@ -344,6 +356,7 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream)
|
|
int err;
|
|
struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
+ struct snd_ac97 *ac97 = cs5535au->ac97;
|
|
|
|
runtime->hw = snd_cs5535audio_capture;
|
|
cs5535au->capture_substream = substream;
|
|
@@ -352,11 +365,29 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream)
|
|
if ((err = snd_pcm_hw_constraint_integer(runtime,
|
|
SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
|
|
return err;
|
|
- return 0;
|
|
+
|
|
+#ifdef CONFIG_OLPC
|
|
+ /* Disable Analog Input */
|
|
+ olpc_ai_enable(ac97, 0);
|
|
+ /* Enable V_ref bias while recording. */
|
|
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT, 0);
|
|
+#endif
|
|
+ return err;
|
|
}
|
|
|
|
static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
|
|
{
|
|
+#ifdef CONFIG_OLPC
|
|
+ struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
|
|
+ struct snd_ac97 *ac97 = cs5535au->ac97;
|
|
+
|
|
+ /* Disable Analog Input */
|
|
+ olpc_ai_enable(ac97, 0);
|
|
+ /* Disable V_ref bias. */
|
|
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1<<AC97_AD_VREFD_SHIFT,
|
|
+ 1<<AC97_AD_VREFD_SHIFT);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
|
|
index 3e4d198..838708f 100644
|
|
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
|
|
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
|
|
@@ -64,18 +64,21 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state)
|
|
int i;
|
|
|
|
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
|
+ snd_pcm_suspend_all(cs5535au->pcm);
|
|
+ snd_ac97_suspend(cs5535au->ac97);
|
|
for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
|
|
struct cs5535audio_dma *dma = &cs5535au->dmas[i];
|
|
- if (dma && dma->substream && !dma->suspended)
|
|
+ if (dma && dma->substream)
|
|
dma->saved_prd = dma->ops->read_prd(cs5535au);
|
|
}
|
|
- snd_pcm_suspend_all(cs5535au->pcm);
|
|
- snd_ac97_suspend(cs5535au->ac97);
|
|
/* save important regs, then disable aclink in hw */
|
|
snd_cs5535audio_stop_hardware(cs5535au);
|
|
|
|
+ if (pci_save_state(pci)) {
|
|
+ printk(KERN_ERR "cs5535audio: pci_save_state failed!\n");
|
|
+ return -EIO;
|
|
+ }
|
|
pci_disable_device(pci);
|
|
- pci_save_state(pci);
|
|
pci_set_power_state(pci, pci_choose_state(pci, state));
|
|
return 0;
|
|
}
|
|
@@ -89,7 +92,12 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
|
|
int i;
|
|
|
|
pci_set_power_state(pci, PCI_D0);
|
|
- pci_restore_state(pci);
|
|
+ if (pci_restore_state(pci) < 0) {
|
|
+ printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
|
|
+ "disabling device\n");
|
|
+ snd_card_disconnect(card);
|
|
+ return -EIO;
|
|
+ }
|
|
if (pci_enable_device(pci) < 0) {
|
|
printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
|
|
"disabling device\n");
|
|
@@ -112,17 +120,17 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
|
|
if (!timeout)
|
|
snd_printk(KERN_ERR "Failure getting AC Link ready\n");
|
|
|
|
- /* we depend on ac97 to perform the codec power up */
|
|
- snd_ac97_resume(cs5535au->ac97);
|
|
/* set up rate regs, dma. actual initiation is done in trig */
|
|
for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
|
|
struct cs5535audio_dma *dma = &cs5535au->dmas[i];
|
|
- if (dma && dma->substream && dma->suspended) {
|
|
+ if (dma && dma->substream) {
|
|
dma->substream->ops->prepare(dma->substream);
|
|
dma->ops->setup_prd(cs5535au, dma->saved_prd);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
+ /* we depend on ac97 to perform the codec power up */
|
|
+ snd_ac97_resume(cs5535au->ac97);
|
|
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
|
|
|
return 0;
|