[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