diff options
Diffstat (limited to 'target/linux/olpc/patches-2.6.23/110-olpc_sound.patch')
| -rw-r--r-- | target/linux/olpc/patches-2.6.23/110-olpc_sound.patch | 414 | 
1 files changed, 414 insertions, 0 deletions
| diff --git a/target/linux/olpc/patches-2.6.23/110-olpc_sound.patch b/target/linux/olpc/patches-2.6.23/110-olpc_sound.patch new file mode 100644 index 000000000..c322e46f5 --- /dev/null +++ b/target/linux/olpc/patches-2.6.23/110-olpc_sound.patch @@ -0,0 +1,414 @@ +Index: linux-2.6.23.17/include/sound/ac97_codec.h +=================================================================== +--- linux-2.6.23.17.orig/include/sound/ac97_codec.h ++++ linux-2.6.23.17/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 */ +Index: linux-2.6.23.17/sound/pci/ac97/ac97_codec.c +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/ac97/ac97_codec.c ++++ linux-2.6.23.17/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 +Index: linux-2.6.23.17/sound/pci/ac97/ac97_patch.c +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/ac97/ac97_patch.c ++++ linux-2.6.23.17/sound/pci/ac97/ac97_patch.c +@@ -1973,8 +1973,9 @@ static const struct snd_kcontrol_new snd + 		.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, +Index: linux-2.6.23.17/sound/pci/cs5535audio/Makefile +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/cs5535audio/Makefile ++++ linux-2.6.23.17/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 +Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.c +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio.c ++++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.c +@@ -145,7 +145,7 @@ static unsigned short snd_cs5535audio_ac + 	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  + 		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  +  + 	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 cs553 + 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_inter +  + 	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_inter + 			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; + 			} + 		} +Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio.h +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio.h ++++ linux-2.6.23.17/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 */ +Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pcm.c +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio_pcm.c ++++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pcm.c +@@ -164,6 +164,7 @@ static int cs5535audio_build_dma_packets + 	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_packet + { + 	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(str + 	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(struc + 	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(struc + 		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( + 	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( + 	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; + } +  +Index: linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pm.c +=================================================================== +--- linux-2.6.23.17.orig/sound/pci/cs5535audio/cs5535audio_pm.c ++++ linux-2.6.23.17/sound/pci/cs5535audio/cs5535audio_pm.c +@@ -64,18 +64,21 @@ int snd_cs5535audio_suspend(struct pci_d + 	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_de + 	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_de + 	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; | 
