⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux-at91rm9200-i2s.c

📁 基于at91rm9200-arm920t下的录放音程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		  	if (cmd == SNDCTL_DSP_STEREO)
			  	val = val ? 2 : 1;
		  	if (val != 1 && val != 2)
			  	return -EINVAL;
		  	audio_channels = val;
		  	break;

	  	case SOUND_PCM_READ_CHANNELS:
		  	put_user(audio_channels, (long *) arg);
		 	break;

	  	case SNDCTL_DSP_SPEED:
		  	get_user(val, (long *) arg);
		  	val = audio_set_dsp_speed(val);
			if (val < 0)
				return -EINVAL;
		  	put_user(val, (long *) arg);
		  	break;

	  	case SOUND_PCM_READ_RATE:
		  	put_user(audio_rate, (long *) arg);
		  	break;

	  	case SNDCTL_DSP_GETFMTS:
		  	put_user(AUDIO_FMT_MASK, (long *) arg);
		  	break;

	  	case SNDCTL_DSP_GETBLKSIZE:
			if(file->f_mode & FMODE_WRITE)
		  		return put_user(audio_fragsize, (long *) arg);
			else		
				return put_user(audio_fragsize, (int *) arg);

	  	case SNDCTL_DSP_SETFRAGMENT:
		        if (file->f_mode & FMODE_WRITE) {	
		  		if (output_stream.buffers)
			  		return -EBUSY;
		  		get_user(val, (long *) arg);
		  		audio_fragsize = 1 << (val & 0xFFFF);
		  		if (audio_fragsize < 16)
			  		audio_fragsize = 16;
		  		if (audio_fragsize > 16384)
			  		audio_fragsize = 16384;
		  		audio_nbfrags = (val >> 16) & 0x7FFF;
				if (audio_nbfrags < 2)
					audio_nbfrags = 2;
		  		if (audio_nbfrags * audio_fragsize > 128 * 1024)
			  		audio_nbfrags = 128 * 1024 / audio_fragsize;
		  		if (audio_setup_buf(&output_stream))
			  		return -ENOMEM;
	
			}
			if (file->f_mode & FMODE_READ) {
				if (input_stream.buffers)
					return -EBUSY;
				get_user(val, (int *) arg);
				audio_fragsize =  1 << (val & 0xFFFF);
				if (audio_fragsize < 16)
					audio_fragsize = 16;
				if (audio_fragsize > 16384)
                                        audio_fragsize = 16384;
                                audio_nbfrags = (val >> 16) & 0x7FFF;
                                if (audio_nbfrags < 2)
                                        audio_nbfrags = 2;
                                if (audio_nbfrags * audio_fragsize > 128 * 1024)
                                        audio_nbfrags = 128 * 1024 / audio_fragsize;
                                if (audio_setup_buf(&input_stream))
                                        return -ENOMEM;

			}
		 	break;

	  	case SNDCTL_DSP_SYNC:
		  	return audio_sync(file);

	  	case SNDCTL_DSP_GETOSPACE:
		{
			audio_stream_t *s = &output_stream;
			audio_buf_info *inf = (audio_buf_info *) arg;
			int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
			int i;
			int frags = 0, bytes = 0;

			if (err)
				return err;
			for (i = 0; i < s->nbfrags; i++) {
				if (atomic_read(&s->buffers[i].sem.count) > 0) {
					if (s->buffers[i].size == 0) frags++;
					bytes += s->fragsize - s->buffers[i].size;
				}
			}
			put_user(frags, &inf->fragments);
			put_user(s->nbfrags, &inf->fragstotal);
			put_user(s->fragsize, &inf->fragsize);
			put_user(bytes, &inf->bytes);
			break;
		}

		case SNDCTL_DSP_GETISPACE:
		{
			audio_stream_t *s = &input_stream;
			audio_buf_info *inf = (audio_buf_info *) arg;
			int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
			int i;
			int frags = 0, bytes = 0;

			if (!(file->f_mode & FMODE_READ))
                                return -EINVAL;

			if (err)
				return err;
			for(i = 0; i < s->nbfrags; i++){
			if (atomic_read(&s->buffers[i].sem.count) > 0)
                                {
                                        if (s->buffers[i].size == s->fragsize)
                                                frags++;
                                        bytes += s->buffers[i].size;
                                }
                        }
			put_user(frags, &inf->fragments);
                        put_user(s->nbfrags, &inf->fragstotal);
                        put_user(s->fragsize, &inf->fragsize);
                        put_user(bytes, &inf->bytes);
                        break;
		}
	  	case SNDCTL_DSP_RESET:
			if (file->f_mode & FMODE_READ) {
                                audio_clear_buf(&input_stream);
                        }
                        if (file->f_mode & FMODE_WRITE) {
                                audio_clear_buf(&output_stream);
                        }
                        return 0;
		case SNDCTL_DSP_NONBLOCK:
			file->f_flags |= O_NONBLOCK;
                        return 0;
	 	case SNDCTL_DSP_POST:
	      	case SNDCTL_DSP_SUBDIVIDE:
	      	case SNDCTL_DSP_GETCAPS:
	      	case SNDCTL_DSP_GETTRIGGER:
	      	case SNDCTL_DSP_SETTRIGGER:
	      	case SNDCTL_DSP_GETIPTR:
	      	case SNDCTL_DSP_GETOPTR:
	      	case SNDCTL_DSP_MAPINBUF:
	      	case SNDCTL_DSP_MAPOUTBUF:
	      	case SNDCTL_DSP_SETSYNCRO:
	      	case SNDCTL_DSP_SETDUPLEX:
		  	return -ENOSYS;
	  	default:
		  	return smdk2410_mixer_ioctl(inode, file, cmd, arg);
	}

	return 0;
}


static int smdk2410_audio_open(struct inode *inode, struct file *file)
{
	int cold = !audio_active;

	DPRINTK("audio_open\n");

	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
		if (audio_rd_refcount || audio_wr_refcount)
			return -EBUSY;
		audio_rd_refcount++;
	} else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
		if (audio_rd_refcount || audio_wr_refcount)
			return -EBUSY;
		audio_wr_refcount++;
	} else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
		if (audio_rd_refcount || audio_wr_refcount)
			return -EBUSY;
		audio_rd_refcount++;
		audio_wr_refcount++;
	} else
		return -EINVAL;

	if (cold) {
		audio_rate = AUDIO_RATE_DEFAULT;
		audio_channels = AUDIO_CHANNELS_DEFAULT;
		audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
		audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
		if ((file->f_mode & FMODE_WRITE)){
				init_s3c2410_iis_bus_tx();
				audio_clear_buf(&output_stream);
		}
		if ((file->f_mode & FMODE_READ)){
				init_s3c2410_iis_bus_rx();
				audio_clear_buf(&input_stream);
		}
	}

	return 0;
}

static int smdk2410_audio_release(struct inode *inode, struct file *file)
{
	AT91PS_SSC pSSC = (AT91PS_SSC)AT91C_VA_BASE_SSC2;
	DPRINTK("audio_release\n");

	if (file->f_mode & FMODE_READ) {
		  	if (audio_rd_refcount == 1) {
				audio_clear_buf(&input_stream);
			  	audio_rd_refcount = 0;
			}
	}

	if(file->f_mode & FMODE_WRITE) {
		  	if (audio_wr_refcount == 1) {
			    	audio_sync(file);
			    	audio_clear_buf(&output_stream);
			    	audio_wr_refcount = 0;
		    	}
	  	}

	pSSC->SSC_TCR  = 0;
	pSSC->SSC_TNCR = 0;
	pSSC->SSC_RCR  = 0;
	pSSC->SSC_RNCR = 0;
	pSSC->SSC_PTCR = (1<<1)|(1<<9);	//disable PDC tx and rx
	pSSC->SSC_CR   = (1<<1)|(1<<9);	//disable tx and rx
	//disable clock
	((AT91PS_SYS)AT91C_VA_BASE_SYS)->PMC_PCDR = (1<<AT91C_ID_SSC2)|(1<<AT91C_ID_TC1);

	return 0;
}

static struct file_operations smdk2410_audio_fops = {
	.owner		= THIS_MODULE,
	.llseek		= smdk2410_audio_llseek,
	.write		= smdk2410_audio_write,
	.read		= smdk2410_audio_read,
	.poll		= smdk2410_audio_poll,
	.ioctl		= smdk2410_audio_ioctl,
	.open		= smdk2410_audio_open,
	.release	= smdk2410_audio_release,
};

static int smdk2410_mixer_open(struct inode *inode, struct file *file)
{
	return 0;
}

static int smdk2410_mixer_release(struct inode *inode, struct file *file)
{
	return 0;
}

static struct file_operations smdk2410_mixer_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.ioctl		= smdk2410_mixer_ioctl,
	.open		= smdk2410_mixer_open,
	.release	= smdk2410_mixer_release,
};

static void init_uda1341(void)
{
	unsigned long flags;
	unsigned char uda_sampling;

  	uda1341_volume = 62 - ((DFT_VOLUME * 61) / 100);
	uda1341_boost = 0;
  	uda_sampling = DATA2_DEEMP_NONE;
	uda_sampling &= ~(DATA2_MUTE);

	local_irq_save(flags);
	L3MOD_HI();
	L3CLK_HI();
	local_irq_restore(flags);
	
	uda1341_l3_address(UDA1341_REG_STATUS);
	uda1341_l3_data(0x60);				//reset uda1341	
	uda1341_l3_data(STAT0_SC_384FS | STAT0_IF_MSB);     // set 384 system clock, MSB
	uda1341_l3_data(STAT1 | STAT1_DAC_GAIN | STAT1_ADC_GAIN | STAT1_ADC_ON | STAT1_DAC_ON);

    uda1341_l3_address(UDA1341_REG_DATA0);
	uda1341_l3_data(DATA0 |DATA0_VOLUME(uda1341_volume));  // maximum volume
	uda1341_l3_data(DATA1 |DATA1_BASS(uda1341_boost)| DATA1_TREBLE(0));
    uda1341_l3_data(uda_sampling);
	uda1341_l3_data(EXTADDR(EXT2));
	uda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)) | EXT2_MIXMODE_CH1);
}

static void __init init_iis_pio(void)
{
	//iis lrclk, clk, dout, din
	((AT91PS_SYS)AT91C_VA_BASE_SYS)->PIOB_ASR = AT91C_PIO_PB12 
						| AT91C_PIO_PB13 
						| AT91C_PIO_PB14
						| AT91C_PIO_PB15;
						//| AT91C_PIO_PB16
						//| AT91C_PIO_PB17;
	((AT91PS_SYS)AT91C_VA_BASE_SYS)->PIOB_PDR = AT91C_PIO_PB12 
						| AT91C_PIO_PB13 
						| AT91C_PIO_PB14
						| AT91C_PIO_PB15;
						//| AT91C_PIO_PB16
						//| AT91C_PIO_PB17;
	//codec clock
	((AT91PS_SYS)AT91C_VA_BASE_SYS)->PIOA_BSR = AT91C_PIO_PA19;
	((AT91PS_SYS)AT91C_VA_BASE_SYS)->PIOA_PDR = AT91C_PIO_PA19;
}

static int __init at91rm9200_uda1341_init(void)
{
//	this_dev = dev;
	int ret;
	
	printk("AT91RM9200-UDA1341 Init\n");
	
	init_iis_pio();

	init_uda1341();

	ret = request_irq(AT91C_ID_SSC2, iis_dma_done_handler, SA_INTERRUPT, 
					"IIS DMA", NULL);
	if(ret < 0) {
		printk(KERN_WARNING AUDIO_NAME_VERBOSE
					": request IIS DMA irq fail, return code:%d\n", ret);
		return -EBUSY;
	}
					
	audio_dev_dsp = register_sound_dsp(&smdk2410_audio_fops, -1);
	audio_dev_mixer = register_sound_mixer(&smdk2410_mixer_fops, -1);

	printk(AUDIO_NAME_VERBOSE " initialized\n");

	return 0;
}

static void __exit at91rm9200_uda1341_exit(void)
{	
	unregister_sound_dsp(audio_dev_dsp);
	unregister_sound_mixer(audio_dev_mixer);
	free_irq(AT91C_ID_SSC2, NULL);
	printk(AUDIO_NAME_VERBOSE " unloaded\n");
//	return 0;
}

#ifdef	MODULE
MODULE_AUTHOR("antiscle http://www.ucdragon.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AT91RM9200 + UDA1341TS driver for OSS");
#endif

module_init(at91rm9200_uda1341_init);
module_exit(at91rm9200_uda1341_exit);
#define at91_ssc_read(a)	((unsigned long) __raw_readl(a))
+#define at91_ssc_write(a,v)	__raw_writel((v),(a))
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
new file mode 100644
index 0000000..089cdc9
--- /dev/null
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -0,0 +1,268 @@
+/*
+ * eti_b1_wm8731  --  SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
+ *
+ * Author:	Frank Mandarino <fmandarino@endrelia.com>
+ *		Endrelia Technologies Inc.
+ * Created:	Mar 29, 2006
+ *
+ * Based on corgi.c by:
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  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.
+ *
+ *  Revision history
+ *    30th Nov 2005   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pio.h>
+#include <asm/arch/gpio.h>
+
+#include "../codecs/wm8731.h"
+#include "at91-pcm.h"
+
+#if 0
+#define	DBG(x...)	printk(KERN_INFO "eti_b1_wm8731:" x)
+#else
+#define	DBG(x...)
+#endif
+
+#define AT91_PIO_TF1	(1 << (AT91_PIN_PB6 - PIN_BASE) % 32)
+#define AT91_PIO_TK1	(1 << (AT91_PIN_PB7 - PIN_BASE) % 32)
+#define AT91_PIO_TD1	(1 << (AT91_PIN_PB8 - PIN_BASE) % 32)
+#define AT91_PIO_RD1	(1 << (AT91_PIN_PB9 - PIN_BASE) % 32)
+#define AT91_PIO_RK1	(1 << (AT91_PIN_PB10 - PIN_BASE) % 32)
+#define AT91_PIO_RF1	(1 << (AT91_PIN_PB11 - PIN_BASE) % 32)
+
+
+static struct clk *pck1_clk;
+static struct clk *pllb_clk;
+
+static int eti_b1_startup(struct snd_pcm_substream *substream)
+{
+	/* Start PCK1 clock. */
+	clk_enable(pck1_clk);
+	DBG("pck1 started\n");
+
+	return 0;
+}
+
+static void eti_b1_shutdown(struct snd_pcm_substream *substream)
+{
+	/* Stop PCK1 clock. */
+	clk_disable(pck1_clk);
+	DBG("pck1 stopped\n");
+}
+
+static struct snd_soc_ops eti_b1_ops = {
+	.startup = eti_b1_startup,
+	.shutdown = eti_b1_shutdown,
+};
+
+
+static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const char *intercon[][3] = {
+
+	/* speaker connected to LHPOUT */
+	{"Ext Spk", NULL, "LHPOUT"},
+
+	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
+	{"MICIN", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Int Mic"},
+
+	/* terminator */
+	{NULL, NULL, NULL},
+};
+
+/*
+ * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
+ */
+static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
+{
+	int i;
+
+	DBG("eti_b1_wm8731_init() called\n");
+
+	/* Add specific widgets */
+	for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) {
+		snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]);
+	}
+
+	/* Set up specific audio path interconnects */
+	for(i = 0; intercon[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, intercon[i][0],
+			intercon[i][1], intercon[i][2]);
+	}
+
+	/* not connected */
+	snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+	snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+
+	/* always connected */
+	snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -