[commit] r2374 - in trunk/linux-2.6.x: arch/arm/mach-nds arch/arm/mach-nds/arm7 include/asm-arm/arch-nds sound/arm

dslinux_sonny_jim at dslinux.in-berlin.de dslinux_sonny_jim at dslinux.in-berlin.de
Tue Dec 16 23:48:13 CET 2008


Author: dslinux_sonny_jim
Date: Tue Dec 16 23:48:13 2008
New Revision: 2374

Log:
Enable preliminary microphone support thanks to sjoemac

Modified:
   trunk/linux-2.6.x/arch/arm/mach-nds/Makefile
   trunk/linux-2.6.x/arch/arm/mach-nds/arm7/main.c
   trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.c
   trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.h
   trunk/linux-2.6.x/include/asm-arm/arch-nds/fifo.h
   trunk/linux-2.6.x/sound/arm/nds-sound.c

Modified: trunk/linux-2.6.x/arch/arm/mach-nds/Makefile
==============================================================================
--- trunk/linux-2.6.x/arch/arm/mach-nds/Makefile	(original)
+++ trunk/linux-2.6.x/arch/arm/mach-nds/Makefile	Tue Dec 16 23:48:13 2008
@@ -20,6 +20,7 @@
 extra-y += arm7/time.o
 extra-y += arm7/spi.o
 extra-y += arm7/sound.o
+extra-y += arm7/microphone.o
 extra-y += arm7/wifi.o
 extra-y += arm7/divide.o
 extra-y += arm7.bin
@@ -33,7 +34,7 @@
 	$(OBJCOPY) -O binary $(obj)/arm7.elf $(obj)/arm7.bin
 	rm -f $(obj)/head.o
 
-arm7obj = $(obj)/arm7/head.o $(obj)/arm7/main.o $(obj)/arm7/time.o $(obj)/arm7/spi.o $(obj)/arm7/sound.o $(obj)/arm7/wifi.o $(obj)/arm7/divide.o
+arm7obj = $(obj)/arm7/head.o $(obj)/arm7/main.o $(obj)/arm7/time.o $(obj)/arm7/spi.o $(obj)/arm7/sound.o $(obj)/arm7/microphone.o $(obj)/arm7/wifi.o $(obj)/arm7/divide.o
 
 $(obj)/arm7.elf: $(arm7obj) $(src)/arm7/arm7.lds
 	$(LD) -nostartfiles -nostdlib -o $(obj)/arm7.elf $(arm7obj) -T $(src)/arm7/arm7.lds

Modified: trunk/linux-2.6.x/arch/arm/mach-nds/arm7/main.c
==============================================================================
--- trunk/linux-2.6.x/arch/arm/mach-nds/arm7/main.c	(original)
+++ trunk/linux-2.6.x/arch/arm/mach-nds/arm7/main.c	Tue Dec 16 23:48:13 2008
@@ -6,6 +6,7 @@
 #include "asm/arch/wifi.h"
 #include "asm/arch/firmware.h"
 
+#include "microphone.h"
 #include "sound.h"
 #include "arm7.h"
 #include "spi.h"
@@ -86,6 +87,30 @@
 				break;
 			}
 			break;
+		case FIFO_MIC:
+			switch (FIFO_MIC_CMD(data)) {
+			case FIFO_MIC_POWER:
+				if (data & 0x1) 
+					mic_on(); 
+				else mic_off();
+				break;
+			case FIFO_MIC_DMA_ADDRESS:
+				mic_set_address(FIFO_MIC_DMA(data));
+				break;
+			case FIFO_MIC_DMA_SIZE:
+				mic_set_size(FIFO_MIC_DATA(data));
+				break;
+			case FIFO_MIC_RATE:
+				mic_set_rate(FIFO_MIC_DATA(data));
+				break;
+			case FIFO_MIC_TRIGGER:
+				if (data & 1)
+					mic_start();
+				else
+					mic_stop();
+				break;
+			}
+			break;
 		case FIFO_WIFI:
 			cmd = FIFO_WIFI_GET_CMD(data);
 			switch (cmd) {
@@ -258,6 +283,13 @@
 		wif &= ~IRQ_TIMER0;
 		wifi_timer_handler();
 	}
+	
+	if (wif & IRQ_TIMER3) {
+		/* Acknowlege Interrupt, send interrupt to mic */
+		NDS_IF = IRQ_TIMER3;
+		wif &= ~IRQ_TIMER3;
+		mic_timer_handler();
+	}
 
 	if (wif & IRQ_ARM9) {
 		/* Acknowledge Interrupt */

Modified: trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.c
==============================================================================
--- trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.c	(original)
+++ trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.c	Tue Dec 16 23:48:13 2008
@@ -18,6 +18,7 @@
 #define SPI_POWER	(0<<8)
 #define SPI_FIRMWARE	(1<<8)
 #define SPI_TOUCH	(2<<8)
+#define SPI_MIC	(2<<8) // TODO Check
 #define SPI_8CLOCKS	(0<<10)
 #define SPI_16CLOCKS	(1<<10)
 #define SPI_SINGLE	(0<<11)
@@ -29,6 +30,12 @@
 #define POWER_WRITE	(0<<7)
 #define POWER_REG(n)	(n)
 
+#define MIC_ON	(1)
+#define MIC_OFF	(0)
+
+#define MIC_POWER_OFFSET	(2)
+
+
 #define WAIT_FOR_NOT_BUSY() {while (REG_SPI_CR & SPI_BUSY) swiDelay(1);}
 
 static u16 touch_read(u32 command)
@@ -150,3 +157,49 @@
 
 	REG_SPI_CR = 0;
 }
+
+/*
+ * mic_on_off() : Turns on/off the Microphone Amp. 
+ * Code based on neimod's example.
+ */
+void mic_on_off(u8 control) {
+	WAIT_FOR_NOT_BUSY();
+
+	REG_SPI_CR = SPI_ENABLE | SPI_POWER | SPI_1MHZ | SPI_CONTINUOUS;
+	REG_SPI_DATA = MIC_POWER_OFFSET;
+
+	WAIT_FOR_NOT_BUSY();
+
+	REG_SPI_CR = SPI_ENABLE | SPI_POWER | SPI_1MHZ;
+	REG_SPI_DATA = control;
+}
+
+/*
+ * mic_read8(): Reads a byte from the microphone
+ * Code based on neimod's example. 
+ */
+u8 mic_read8() {
+	u16 result, result2;
+
+	WAIT_FOR_NOT_BUSY();
+
+	REG_SPI_CR = SPI_ENABLE | SPI_MIC | SPI_2MHZ | SPI_CONTINUOUS;
+	REG_SPI_DATA = 0xEC;  // Touchscreen command format for AUX
+
+	WAIT_FOR_NOT_BUSY();
+
+	REG_SPI_DATA = 0x00;
+
+	WAIT_FOR_NOT_BUSY();
+
+	result = REG_SPI_DATA;
+	REG_SPI_CR = SPI_ENABLE | SPI_TOUCH | SPI_2MHZ;
+	REG_SPI_DATA = 0x00;
+
+	WAIT_FOR_NOT_BUSY();
+
+	result2 = REG_SPI_DATA;
+
+	return (((result & 0x7F) << 1) | ((result2>>7)&1));
+
+}

Modified: trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.h
==============================================================================
--- trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.h	(original)
+++ trunk/linux-2.6.x/arch/arm/mach-nds/arm7/spi.h	Tue Dec 16 23:48:13 2008
@@ -22,4 +22,7 @@
 
 void read_firmware(u32 address, u8 * destination, int count);
 
+void mic_on_off(u8 control);
+u8 mic_read8(void);
+
 #endif

Modified: trunk/linux-2.6.x/include/asm-arm/arch-nds/fifo.h
==============================================================================
--- trunk/linux-2.6.x/include/asm-arm/arch-nds/fifo.h	(original)
+++ trunk/linux-2.6.x/include/asm-arm/arch-nds/fifo.h	Tue Dec 16 23:48:13 2008
@@ -109,6 +109,22 @@
 #define FIFO_SOUND_TRIGGER	(6<<24)
 #define FIFO_SOUND_POWER	(7<<24)
 
+/*
+ * Mic Commands
+ * +-------------------------------------------------------+
+ * |3 bits FIFO_MIC | 1bit unused | 28 bits command data   |
+ * +-------------------------------------------------------+
+ */
+#define FIFO_MIC_CMD(d)	(d & 0x0f000000)
+#define FIFO_MIC_DATA(d)	(d & 0x00ffffff)
+#define FIFO_MIC_DMA(d)	(FIFO_MIC_DATA(d) + 0x02000000)
+
+#define FIFO_MIC_DMA_ADDRESS	(2<<24) //FIFO_DMA_ADDRESS
+#define FIFO_MIC_DMA_SIZE	(3<<24) //FIFO_DMA_SIZE
+#define FIFO_MIC_RATE	(5<<24) //FIFO_SOUND_RATE
+#define FIFO_MIC_TRIGGER	(6<<24) //FIFO_SOUND_TRIGGER
+#define FIFO_MIC_POWER	(7<<24) //FIFO_SOUND_POWER
+
 /* FIFO registers */
 #define NDS_REG_IPCFIFOSEND (*(volatile u32*) 0x04000188)
 #define NDS_REG_IPCFIFORECV (*(volatile u32*) 0x04100000)

Modified: trunk/linux-2.6.x/sound/arm/nds-sound.c
==============================================================================
--- trunk/linux-2.6.x/sound/arm/nds-sound.c	(original)
+++ trunk/linux-2.6.x/sound/arm/nds-sound.c	Tue Dec 16 23:48:13 2008
@@ -26,6 +26,7 @@
 #define TIMER_CASCADE	(TIMER_ENABLE|(1<<2))
 
 #define DMA_BUFFERSIZE	(128*1024)
+#define DMA_BUFFERSIZE_CAPTURE (32768)
 
 /* module parameters (see "Module Parameters") */
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -35,6 +36,8 @@
 /* DMA-capable sample buffer */
 /* This buffer is aligned to the ARM9 cache lines */
 static char samplebuf[DMA_BUFFERSIZE] __attribute__ ((aligned (32)));
+static char capturebuf[DMA_BUFFERSIZE_CAPTURE] __attribute__ ((aligned (32)));
+
 
 MODULE_AUTHOR("Malcolm Parsons <malcolm.parsons at gmail.com>");
 MODULE_LICENSE("GPL");
@@ -74,7 +77,7 @@
 	.info = (SNDRV_PCM_INFO_MMAP |
 		 SNDRV_PCM_INFO_NONINTERLEAVED |
 		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
-	.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_U16_LE,
+	.formats = SNDRV_PCM_FMTBIT_U8 /*| SNDRV_PCM_FMTBIT_U16_LE*/,
 	.rates = SNDRV_PCM_RATE_8000_48000,
 	.rate_min = 8000,
 	.rate_max = 48000,
@@ -88,7 +91,7 @@
 };
 
 /* Set the sample format */
-void nds_set_sample_format(struct nds *chip, snd_pcm_format_t format)
+void nds_playback_set_sample_format(struct nds *chip, snd_pcm_format_t format)
 {
 	switch (format) {
 	case SNDRV_PCM_FORMAT_S8:
@@ -106,25 +109,37 @@
 }
 
 /* Set the sample rate */
-void nds_set_sample_rate(struct nds *chip, unsigned int rate)
+void nds_playback_set_sample_rate(struct nds *chip, unsigned int rate)
 {
 	nds_fifo_send(FIFO_SOUND | FIFO_SOUND_RATE | rate);
 }
 
+void nds_capture_set_sample_rate(struct nds *chip, unsigned int rate)
+{
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_RATE | rate);
+}
+
 /* Set the number of channels */
-void nds_set_channels(struct nds *chip, unsigned int channels)
+void nds_playback_set_channels(struct nds *chip, unsigned int channels)
 {
 	nds_fifo_send(FIFO_SOUND | FIFO_SOUND_CHANNELS | channels);
 }
 
 /* Setup the DMA */
-void nds_set_dma_setup(struct nds *chip, unsigned char *dma_area,
+void nds_playback_set_dma_setup(struct nds *chip, unsigned char *dma_area,
 		       size_t buffer_size, size_t period_size)
 {
 	nds_fifo_send(FIFO_SOUND | FIFO_SOUND_DMA_SIZE | buffer_size);
 	nds_fifo_send(FIFO_SOUND | FIFO_SOUND_DMA_ADDRESS |
-	    (((u32) dma_area) & 0xffffff));
+		(((u32) dma_area) & 0xffffff));
+}
 
+void nds_capture_set_dma_setup(struct nds *chip, unsigned char *dma_area,
+			       size_t buffer_size, size_t period_size)
+{
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_DMA_SIZE | buffer_size);
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_DMA_ADDRESS |
+		(((u32) dma_area) & 0xffffff));
 }
 
 /* open callback */
@@ -161,17 +176,31 @@
 /* open callback */
 static int snd_nds_capture_open(snd_pcm_substream_t * substream)
 {
+	struct nds *chip = snd_pcm_substream_chip(substream);
+
 	snd_pcm_runtime_t *runtime = substream->runtime;
+
 	runtime->hw = snd_nds_capture_hw;
-	// more hardware-initialization will be done here
+	spin_lock(&chip -> lock);
+
+	chip -> substream = substream;
+
+	//turn on the mic power.
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_POWER | 1);
+
+	spin_unlock(&chip -> lock);
 	return 0;
 }
 
 /* close callback */
-static int snd_nds_capture_close(snd_pcm_substream_t * substream)
+static int snd_nds_capture_close(snd_pcm_substream_t * substream) 
 {
-	// the hardware-specific codes will be here
-	return 0;
+	// turn off the power to the mic and clear the timer.
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_POWER | 0);
+	
+	TIMER1_CR=0;
+	TIMER2_CR=0;
+  return 0;
 }
 
 /* hw_params callback */
@@ -189,7 +218,7 @@
 }
 
 /* prepare callback */
-static int snd_nds_pcm_prepare(snd_pcm_substream_t * substream)
+static int snd_nds_playback_prepare(snd_pcm_substream_t * substream)
 {
 	struct nds *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -219,25 +248,75 @@
 		break;
 	}
 
-	nds_set_channels(chip, runtime->channels);
-	nds_set_sample_format(chip, runtime->format);
-	nds_set_sample_rate(chip, runtime->rate);
-	nds_set_dma_setup(chip, runtime->dma_area,
+	nds_playback_set_channels(chip, runtime->channels);
+	nds_playback_set_sample_format(chip, runtime->format);
+	nds_playback_set_sample_rate(chip, runtime->rate);
+	nds_playback_set_dma_setup(chip, runtime->dma_area,
 			  chip->buffer_size, chip->period_size);
 	chip->period = 0;
 
 	return 0;
 }
 
+static int snd_nds_capture_prepare(snd_pcm_substream_t * substream)
+{
+	struct nds *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	/* set up the hardware with the current configuration
+	 * for example...
+	 */
+
+	chip->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+	chip->period_size = snd_pcm_lib_period_bytes(substream);
+
+	TIMER1_CR = 0;
+	TIMER2_CR = 0;
+	/* use exactly the same formula as for ARM7, to get the
+	   same period regarding rounding errors */
+	TIMER1_DATA = 0 - ((0x1000000 / runtime->rate)*2);
+
+	TIMER2_DATA = 0 - (chip -> period_size / runtime -> channels);
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_U8:
+	case SNDRV_PCM_FORMAT_S8:
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_IMA_ADPCM:
+	  break;
+	default:
+	  printk("Error format is not handled?%d\n",runtime -> format);
+		break;
+	}
+
+	//nds_playback_set_channels(chip, runtime->channels);
+	//nds_playback_set_sample_format(chip, runtime->format);
+	nds_capture_set_sample_rate(chip, runtime->rate);
+	nds_capture_set_dma_setup(chip, capturebuf,
+				   chip->buffer_size, chip->period_size);
+	chip->period = 0;
+
+	return 0;
+
+
+}
 /* trigger callback */
 static int snd_nds_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	int target;
+	if (substream -> stream == SNDRV_PCM_STREAM_CAPTURE)
+	{
+		target = FIFO_MIC;
+	}
+	else 
+	{
+		target = FIFO_SOUND;
+	}
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		// start the PCM engine
-		nds_fifo_send(FIFO_SOUND | FIFO_SOUND_TRIGGER | 1);
+		nds_fifo_send(target | FIFO_SOUND_TRIGGER | 1);
 
 		/* wait until we know for shure that the ARM7 has 
 		   started the sound output */
@@ -256,7 +335,7 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		// stop the PCM engine
-		nds_fifo_send(FIFO_SOUND | FIFO_SOUND_TRIGGER | 0);
+		nds_fifo_send(target | FIFO_SOUND_TRIGGER | 0);
 		TIMER1_CR = 0;
 		TIMER2_CR = 0;
 		break;
@@ -276,6 +355,18 @@
 	return chip->period * runtime->period_size;
 }
 
+static int capture_copy(snd_pcm_substream_t *substream, int channel,
+			snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count)
+{
+	int i;
+	char* cdst = (char*)dst;
+	for (i=0;i<count;i++)
+	{
+		cdst[i] = capturebuf[pos+i];
+	}
+	return 0;
+}
+
 /* operators */
 static snd_pcm_ops_t snd_nds_playback_ops = {
 	.open = snd_nds_playback_open,
@@ -283,7 +374,7 @@
 	.ioctl = snd_pcm_lib_ioctl,
 	.hw_params = snd_nds_pcm_hw_params,
 	.hw_free = snd_nds_pcm_hw_free,
-	.prepare = snd_nds_pcm_prepare,
+	.prepare = snd_nds_playback_prepare,
 	.trigger = snd_nds_pcm_trigger,
 	.pointer = snd_nds_pcm_pointer,
 };
@@ -295,9 +386,10 @@
 	.ioctl = snd_pcm_lib_ioctl,
 	.hw_params = snd_nds_pcm_hw_params,
 	.hw_free = snd_nds_pcm_hw_free,
-	.prepare = snd_nds_pcm_prepare,
+	.prepare = snd_nds_capture_prepare,
 	.trigger = snd_nds_pcm_trigger,
 	.pointer = snd_nds_pcm_pointer,
+	.copy = capture_copy,
 };
 
 /*
@@ -310,7 +402,7 @@
 	snd_pcm_substream_t *substream;
 	int err;
 
-	if ((err = snd_pcm_new(chip->card, "NDS", 0, 1, 0, &pcm)) < 0)
+	if ((err = snd_pcm_new(chip->card, "NDS", 0, 1, 1, &pcm)) < 0)
 		return err;
 
 	pcm->private_data = chip;
@@ -330,6 +422,16 @@
 	substream->buffer_bytes_max    = DMA_BUFFERSIZE;
 	substream->dma_max             = DMA_BUFFERSIZE;
 
+	/* set the DMA buffer for the capture substream */
+	substream = pcm -> streams[1].substream;
+	substream -> dma_buffer.dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+	substream -> dma_buffer.dev.dev  = snd_dma_continuous_data(GFP_DMA);
+	substream -> dma_buffer.bytes    = DMA_BUFFERSIZE_CAPTURE;
+	substream -> dma_buffer.area     = capturebuf;
+	substream -> dma_buffer.addr     = (unsigned long)capturebuf;
+	substream -> buffer_bytes_max    = DMA_BUFFERSIZE_CAPTURE;
+	substream -> dma_max             = DMA_BUFFERSIZE_CAPTURE;
+
 	return 0;
 }
 
@@ -363,6 +465,7 @@
 {
 	// turn the power off
 	nds_fifo_send(FIFO_SOUND | FIFO_SOUND_POWER | 0);
+	nds_fifo_send(FIFO_MIC | FIFO_MIC_POWER | 0);
 	kfree(chip);
 	return 0;
 }


More information about the dslinux-commit mailing list