linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* I2S driver
@ 2008-03-03 12:08 Angelo
  2008-03-03 12:40 ` Roman Fietze
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Angelo @ 2008-03-03 12:08 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 316 bytes --]

Hi my name is Angelo. 

I'm working on I2S driver, on MPC5200b board. 
Does anyone tell me where i can found some information on HOW to write it?

Thanks for help.



       
---------------------------------

---------------------------------
L'email della prossima generazione? Puoi averla con la nuova Yahoo! Mail

[-- Attachment #2: Type: text/html, Size: 486 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread
* i2s driver
@ 2008-03-03 13:18 Angelo
  0 siblings, 0 replies; 19+ messages in thread
From: Angelo @ 2008-03-03 13:18 UTC (permalink / raw)
  To: Linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1005 bytes --]

Thanks for answer.

>I can also send you some GPL'd code that works.
>It is extremely bad commented (:-p) and probably not useful
> (it's not an ALSA driver itself, but it uses the DMA to
> copy data to the PSC - I2S mode) but it works. 

It is a great idea; i can use it to start. 
You can send it via mail..

> But this code is based on 2.6.16 kernel.

I'm using 2.6.22 kernel version.

I just enabled in lite5200b.dts:

//PSC3 in CODEC mode example  //asimmini
i2s@2400 {  // PSC3
 device_type = "sound";
 compatible = "mpc5200b-psc-i2s";//not 5200 compatible
 cell-index = <2>;
 reg = <2400 100>;
 interrupts = <2 3 0>;
 interrupt-parent = <&mpc5200_pic>;
};

..and added in lite5200.c, in function mpc52xx_psc_functions
...
struct mpc52xx_psc_func mpc52xx_psc_functions[]= {
{       .id     = 2,  
        .func   = "i2s",
},
...
thanks for help.




       
---------------------------------

---------------------------------
L'email della prossima generazione? Puoi averla con la nuova Yahoo! Mail

[-- Attachment #2: Type: text/html, Size: 1567 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread
* I2S driver
@ 2008-03-03 17:05 Angelo
  2008-03-03 17:14 ` Phillip Lougher
  2008-03-03 20:50 ` Timur Tabi
  0 siblings, 2 replies; 19+ messages in thread
From: Angelo @ 2008-03-03 17:05 UTC (permalink / raw)
  To: Linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 400 bytes --]


Timur wrote:
>I wrote an ASoC driver for the MPC8610, which also has 
>an I2S interface.  You can find it in sound/soc/fsl.

in my kernel version (2.6.22) there isn't any folder named
fsl in sound/soc/

So where i can found it?

thanks for help.




       
---------------------------------

---------------------------------
L'email della prossima generazione? Puoi averla con la nuova Yahoo! Mail

[-- Attachment #2: Type: text/html, Size: 597 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread
* I2S driver
@ 2008-03-04 10:26 Angelo
  2008-03-04 13:23 ` Pedro Luis D. L.
  0 siblings, 1 reply; 19+ messages in thread
From: Angelo @ 2008-03-04 10:26 UTC (permalink / raw)
  To: Linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 908 bytes --]


Angelo wrote:
> Timur wrote:
>>I wrote an ASoC driver for the MPC8610, which also has 
>>an I2S interface.  You can find it in sound/soc/fsl.
> 
> in my kernel version (2.6.22) there isn't any folder named
> fsl in sound/soc/

> Timur wrote:
> It's in 2.6.25.


The main problem is that in the feature of MPC8610 you can find:
  Two synchronous serial interface (SSI) controllers for I2S or AC97   
  audio     inputs/outputs

while in MPC5200b's feature there's only:
  I2S (up to three)
However the main difference features:
MPC5200B: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPC5200B&nodeId=0162468rH3bTdG0898
MPC8610:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MPC8610

What do you think on this difference?




       
---------------------------------

---------------------------------
L'email della prossima generazione? Puoi averla con la nuova Yahoo! Mail

[-- Attachment #2: Type: text/html, Size: 1843 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread
* RE: I2S driver
@ 2008-03-05 12:36 Pedro Luis D. L.
  2008-03-06 10:27 ` Angelo
  0 siblings, 1 reply; 19+ messages in thread
From: Pedro Luis D. L. @ 2008-03-05 12:36 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 504 bytes --]


Angelo wrote:
>
> Pedro wrote:
>>Which library do you mean? I don't understand, sorry.
>
> In your previous mail (with code), each lines with an "#include " don't show the name of header file.
>
> thanks
>
Ups! Sorry, I send the code as an attached file, then.
>
>
> ________________________________
> L'email della prossima generazione? Puoi averla con la Nuova Yahoo! Mail

_________________________________________________________________
MSN Video. 
http://video.msn.com/?mkt=es-es

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mpc52xx_spi.c --]
[-- Type: text/x-csrc, Size: 18977 bytes --]

/***************************************************************************
 *   Copyright (C) 2007 by Pedro L. Domínguez                              *
 *   pedro.dominguez@aed-engineering.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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   History                                                               *
 *     Original Version by Bernhard Kuhn <bkuhn@freescale.com>             *
 *            for 2.6.16 kernel                                            *
 ***************************************************************************/

#define SPI_DBG

#ifdef SPI_DBG
#define DBG(x...) printk("(debug) " x)
#else
#define DBG(x...)
#endif

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/string.h>
#include <linux/autoconf.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/delay.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#include <asm/of_platform.h>
#include <sysdev/bestcomm/bestcomm.h>
#include <sysdev/bestcomm/gen_bd.h>
#include <sysdev/bestcomm/bestcomm_priv.h>
#include <sound/pcm.h>
#include <sound/asound.h>
// #include <sound/typedefs.h>

#define BPF             2      // bytes per frame
#define SLOTS           2
#define SAMPLESIZE      (BPF*SLOTS)
#define FPP             1024   // bytes per copy period 
#define PERIODS         8      // periods
#define PERIODSIZE      (SAMPLESIZE/2*FPP)
#define BUFSIZE         (SAMPLESIZE*FPP*PERIODS)
#define FPP_HW          128
//512    // 10 ms
#define PERIODS_HW      8      // periods
#define PERIODSIZE_HW   (SAMPLESIZE*FPP_HW)

#define FIFOSIZE	512
#define RX_GRAN		4
#define TX_GRAN		4
#define	RX_ALARM	0x120
#define	TX_ALARM	FIFOSIZE - (TX_GRAN * 4) - 208

#define DELAY_TIME_SLOT 0x20000000
#define GEN_CLK_INT 0x00800000
#define MULTIWD_ENABLE 0x00400000
#define CLK_POL_RISING 0x00200000

#define PROCFS_NAME	"MPC52xx_SPI"
#define MCLKEN_DIV 0x8001
#define DRV_NAME "mpc52xx-psc-spi"
#define PROCFS_MAX_SIZE		1024
#define BUF_FRAMES 300

/* MBAR position */
#define MPC52xx_MBAR		0xf0000000	/* Phys address */
#define MPC52xx_MBAR_VIRT	0xf0000000	/* Virt address */
#define MPC52xx_MBAR_SIZE	0x00010000

#define MPC52xx_PA(x)		((phys_addr_t)(MPC52xx_MBAR + (x)))
#define MPC52xx_VA(x)		((void __iomem *)(MPC52xx_MBAR_VIRT + (x)))

/* Registers zone offset/size  */
#define MPC52xx_MMAP_CTL_OFFSET		0x0000
#define MPC52xx_MMAP_CTL_SIZE		0x068
#define MPC52xx_SDRAM_OFFSET		0x0100
#define MPC52xx_SDRAM_SIZE		0x010
#define MPC52xx_CDM_OFFSET		0x0200
#define MPC52xx_CDM_SIZE		0x038
#define MPC52xx_INTR_OFFSET		0x0500
#define MPC52xx_INTR_SIZE		0x04c
#define MPC52xx_GPTx_OFFSET(x)		(0x0600 + ((x)<<4))
#define MPC52xx_GPT_SIZE		0x010
#define MPC52xx_RTC_OFFSET		0x0800
#define MPC52xx_RTC_SIZE		0x024
#define MPC52xx_GPIO_OFFSET		0x0b00
#define MPC52xx_GPIO_SIZE		0x040
#define MPC52xx_GPIO_WKUP_OFFSET	0x0c00
#define MPC52xx_GPIO_WKUP_SIZE		0x028
#define MPC52xx_PCI_OFFSET		0x0d00
#define MPC52xx_PCI_SIZE		0x100
#define MPC52xx_SDMA_OFFSET		0x1200
#define MPC52xx_SDMA_SIZE		0x100
#define MPC52xx_XLB_OFFSET		0x1f00
#define MPC52xx_XLB_SIZE		0x100
#define MPC52xx_PSCx_OFFSET(x)		(((x)!=6)?(0x1e00+((x)<<9)):0x2c00)
#define MPC52xx_PSC_SIZE		0x0a0
#define PORT_CONFIG_PSC1		0x00000006
#define PSC1_CLK_EN			0x00000020

typedef unsigned long		uint32;
typedef unsigned long		UInteger32;
typedef unsigned short 		UInteger16;

struct proc_dir_entry *Our_Proc_File;

struct SPI_buffer {
	char *va;
	dma_addr_t pa;
};

static struct SPI_buffer SPI_tx_silence;
static struct SPI_buffer SPI_rx_bufs;

typedef struct _node {
   struct SPI_buffer buffer;
   struct _node *next;
} Node;

static Node *LastNode;
static Node *FirstNode;
Node *FirstNodeFree;
Node *LastNodeFree;

struct bcom_task *tx_bcom;
struct bcom_task *rx_bcom;
int r_irq;
int t_irq;

struct mpc52xx_psc *psc;

struct mpc52xx_spi_priv {
	struct device *dev;
	resource_size_t	mem_start;
	resource_size_t mem_len;
	int irq;
	struct mpc52xx_psc __iomem *psc;

	struct bcom_task *tsk_tx;
	spinlock_t dma_lock;

	int period_byte_size;
	u32 period_start, period_end, period_next_p;
};

static int initiator_tx;
static int initiator_rx;

static struct snd_pcm_substream *snd_SPI_substream;
static int snd_SPImgt_running = 0;
static int snd_SPImgt_started = 2;
static int SPI_pos = 0;
static int SPI_play = 0;
static int nodecounter=0;
static unsigned int dmablockcounter=0;

static struct hrtimer start_timer;
static struct timeval tclockup = {.tv_sec = 1,.tv_usec = 0};
static struct timeval tclockdown= {.tv_sec = 0,.tv_usec = 615080};
static ktime_t kt_timedown, kt_timeup ;

void (*hook_per_elap)(int, int);
UInteger32 (*hook_frames_rcv)(void);

int SPI_buffers_init(void) {
	int i;
 	Node *node;


	FirstNodeFree = (Node *)kmalloc(sizeof(Node), GFP_KERNEL);	
	FirstNodeFree->buffer.va = kmalloc(PERIODSIZE_HW, GFP_DMA);
	FirstNodeFree->buffer.pa = virt_to_phys((void *)FirstNodeFree->buffer.va);
	node = FirstNodeFree;

	for (i=1;i<BUF_FRAMES;i++)
	{
		node->next = (Node *)kmalloc(sizeof(Node), GFP_KERNEL);	
		node->next->buffer.va = kmalloc(PERIODSIZE_HW, GFP_DMA);
		node->next->buffer.pa = virt_to_phys((void *)node->next->buffer.va);
		node = node->next;
	}
	LastNodeFree = node;
	LastNodeFree->next=NULL;
	DBG("SPI_buffers_init()\n");
	// prepare reception buffer	
	SPI_rx_bufs.va = kmalloc(BUFSIZE, GFP_DMA);

	SPI_rx_bufs.pa = virt_to_phys((void *)SPI_rx_bufs.va);

	// prepare silence buffer
	SPI_tx_silence.va = kmalloc(BUFSIZE, GFP_DMA);

	SPI_tx_silence.pa = virt_to_phys((void *)SPI_tx_silence.va);

	memset(SPI_tx_silence.va,0,BUFSIZE);

	return 0;
}

int snd_SPI_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
#ifdef SND_I2S_DEBUG
	printk("snd_SPI_pcm_trigger\n");
#endif
	switch (cmd) {
		case SNDRV_PCM_TRIGGER_START:
		case SNDRV_PCM_TRIGGER_RESUME:
#ifdef SND_I2S_DEBUG
			printk("START\n");
#endif
			snd_SPI_substream=substream;
			snd_SPImgt_started=2;
			snd_SPImgt_running=1;

			break;
		case SNDRV_PCM_TRIGGER_STOP:
		case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef SND_I2S_DEBUG
			printk("STOP\n");
#endif
			snd_SPImgt_running=0;
			break;

		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
			printk("  PAUSE_PUSH\n");
			break;
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			printk("  PAUSE_RELEASE\n");
			break;
		default:
			return -EINVAL;
	}
	return 0;
};

EXPORT_SYMBOL(snd_SPI_pcm_trigger);


static irqreturn_t SPI_rx_irq(int irq, void *dev_id) {
	// no need for TaskIntClear(rxtask), OS masks and acks IRQ

	struct mpc52xx_spi_priv *priv = dev_id;

	spin_lock(&priv->dma_lock);
	while (bcom_buffer_done(rx_bcom)) {
		struct bcom_gen_bd *bd;
		bcom_retrieve_buffer(rx_bcom, NULL, NULL);
		/* Submit a new one */
		bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(rx_bcom);
		bd->status = 512;
		bd->buf_pa = SPI_rx_bufs.pa;
		
		bcom_submit_next_buffer(rx_bcom, NULL);
		bcom_enable(rx_bcom);
	}
	spin_unlock(&priv->dma_lock);
	return IRQ_HANDLED;
};

static irqreturn_t SPI_tx_irq(int irq, void *dev_id) {
	// no need for TaskIntClear(txtask), OS masks and acks IRQ
	struct mpc52xx_spi_priv *priv = dev_id;
	struct bcom_gen_bd *bd;

	Node *node;

	if(psc->mpc52xx_psc_status&0x1800) {

		printk("PSC Reset\n");
		psc->command = MPC52xx_PSC_RST_RX;
		psc->command = MPC52xx_PSC_RST_TX;
		psc->command = MPC52xx_PSC_SEL_MODE_REG_1;
		psc->command = MPC52xx_PSC_RST_ERR_STAT;
		psc->command = MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE;
	};
	
	spin_lock(&priv->dma_lock);
	
	for(;;)
	{
		if(!bcom_buffer_done(tx_bcom)) {
			break;
		}
		bcom_retrieve_buffer(tx_bcom, NULL, NULL);
		/* Submit a new one */
		bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(tx_bcom);

		if (snd_SPImgt_running)
		{
			if((FirstNode == NULL)) {
				bd->status = PERIODSIZE_HW;
				bd->buf_pa = SPI_tx_silence.pa;
				bcom_submit_next_buffer(tx_bcom, NULL);
				
				if(hook_per_elap != NULL) {
					hook_per_elap(SPI_pos, SPI_play);
				}
			} 
			else
			{
				node=FirstNode;
				FirstNode=node->next;
				if(FirstNode==NULL)LastNode=NULL;
				bd->status = PERIODSIZE_HW;
				bd->buf_pa = (void *)(((u32)node->buffer.pa));
				bcom_submit_next_buffer(tx_bcom, NULL);
				node->next=NULL;
				if(LastNodeFree!=NULL)
					LastNodeFree->next=node;
				LastNodeFree=node;					
				if(FirstNodeFree==NULL)FirstNodeFree=LastNodeFree;
				nodecounter--;
			}
			dmablockcounter++;

		} else {
			bd->status = PERIODSIZE_HW;
			bd->buf_pa = SPI_tx_silence.pa;
			bcom_submit_next_buffer(tx_bcom, NULL);

		}
		bcom_enable(tx_bcom);

	}
	spin_unlock(&priv->dma_lock);

	return IRQ_HANDLED;
};

typedef struct {
	unsigned short l;
	unsigned short r;
} sample_t;

static int frame=0;
static Node *nodebuild;
static int counter =0;
static int *ptr=NULL;

int snd_SPI_pcm_copy(struct snd_pcm_substream *substream,
		int voice,
		snd_pcm_uframes_t pos,
		void *src,
		snd_pcm_uframes_t count) {

	snd_pcm_uframes_t i;
// 	sample_t* data = (sample_t*) src;
	UInteger32 *data = (UInteger32 *) src;

	int cnt=count;
// 	unsigned short aux;

//   	printk("1.cnt %d, frame %d\n",cnt, frame); 
	while (cnt > 0)
	{
		counter++;
		if(counter == 1000){

// 			printk("Frames: %d\n",nodecounter);
			counter=0;

		}
		if(ptr==NULL)
		{ 

			if(FirstNodeFree != NULL)
			{
				nodebuild = FirstNodeFree;
				FirstNodeFree = FirstNodeFree->next;
				if(FirstNodeFree==NULL)LastNodeFree=NULL;		
			}
			else
			{			
				nodebuild = (Node *)kmalloc(sizeof(Node), GFP_KERNEL);	
				nodebuild->buffer.va = kmalloc(PERIODSIZE_HW, GFP_DMA);
				nodebuild->buffer.pa = virt_to_phys((void *)nodebuild->buffer.va);
				nodebuild->next=NULL;
// 				printk("Getting more Frames buffers, num of nodes %d\n",nodecounter);
			}			
			ptr=(int *)nodebuild->buffer.va;
			frame=0;	
		}
//   		printk("2.cnt %d, frame %d\n",cnt, frame); 
		if(cnt >= (FPP_HW -frame))
		{

			for(i=0;i<(FPP_HW-frame);i++) {
// 				printk(" 0x%04x ",data->l);
// 				printk(" 0x%04x ",data->r);	
//Big Endian
// 				aux=((data->l>>8)&0xff)+((data->l << 8)&0xff00);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)) = (aux<<16);
// 				aux=((data->r>>8)&0xff)+((data->r << 8)&0xff00);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)+1) = (aux<<16);
//Little Endian
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)) = (data->l<<16);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)+1) = (data->r<<16);
//Raw Data			
// 				printk("src: 0x%08x\n", *(UInteger32 *)data);
				*(ptr+i) = *(UInteger32 *)data;
				data++;
			};
			cnt=cnt-(FPP_HW-frame);
			frame=0;			
			ptr=NULL;
			nodebuild->next=NULL;
			if(LastNode != NULL) LastNode->next = nodebuild;
			if(FirstNode == NULL) FirstNode = nodebuild;
			LastNode = nodebuild;
			nodecounter++;
//   			printk("3.cnt %d, frame %d\n",cnt, frame); 
		}
		else
		{
			for(i=0;i<cnt;i++) {
// 				printk("%04x ",data->l);
// 				printk("%04x ",data->r);
//Big Endian
// 				aux=((data->l>>8)&0xff)+((data->l << 8)&0xff00);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)) = (aux<<16);
// 				aux=((data->r>>8)&0xff)+((data->r << 8)&0xff00);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)+1) = (aux<<16);
//Little Endian
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)) = (data->l<<16);
// 				*(ptr+(i*SLOTS)+(frame*SLOTS)+1) = (data->r<<16);
//Raw Data
				*(ptr+i) = *(UInteger32 *)data;
				data++;
// 				printk("f\n");
			}
			frame=cnt+frame;
			cnt=0;
//   			printk("4.cnt %d, frame %d\n",cnt, frame); 
		}					
	}
	return 0;
};

EXPORT_SYMBOL(snd_SPI_pcm_copy);

static enum hrtimer_restart timer_funct (void *data) {

	static unsigned int counter = 0;
	static unsigned int start = 0;
	UInteger32 framesnum;
	static int diff=0;

	counter = dmablockcounter*128;
	dmablockcounter=0;
	framesnum=hook_frames_rcv();
// 	printk("Frequenz=%d\n",framesnum);
	if(snd_SPImgt_running){
		diff=diff+counter-framesnum;
		start=1;
		
	
	}
	else
	{
		start=0;
	}
	hrtimer_forward(&start_timer, hrtimer_cb_get_time(&start_timer),kt_timeup);

	return HRTIMER_RESTART;
}

static void SPI_setup(void)
{
// 	printk("SPI_setup()\n");
	int psc_num = 1, rv;
	phys_addr_t rx_fifo;
	phys_addr_t tx_fifo;
	struct bcom_bd *bd;
	struct mpc52xx_spi_priv *priv;
	uint32 SICR;
	struct mpc52xx_cdm __iomem *cdm;

	priv = (struct mpc52xx_spi_priv *)kmalloc(sizeof(struct mpc52xx_spi_priv), GFP_KERNEL);

	struct mpc52xx_gpio __iomem *gpio =
		(struct mpc52xx_gpio __iomem *) MPC52xx_PA(MPC52xx_GPIO_OFFSET);

	switch(psc_num) {
		case 1:
			initiator_tx = BCOM_INITIATOR_PSC1_TX;
			initiator_rx = BCOM_INITIATOR_PSC1_RX;
			break;
		case 2:
			initiator_tx = BCOM_INITIATOR_PSC2_TX;
			initiator_rx = BCOM_INITIATOR_PSC2_RX;
			break;
		default:
			panic("snd-SPImgt.o: invalid value for psc_num (%i)\n",psc_num);
			break;
	};

// 	printk("Before request mem region\n");
	if (!request_mem_region(0xF0002000, 0x00000100, DRV_NAME)) {
		printk(KERN_ERR DRV_NAME ": request_mem_region failed\n");
		rv = -EBUSY;
	}

// 	printk("Before ioremaps\n");
	psc = ioremap(MPC52xx_PA(MPC52xx_PSCx_OFFSET(1)), MPC52xx_PSC_SIZE);
	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
	cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);

	psc->tfdata = 0xF0010000; 		 // Power-down [Table 1, MAX5712 Datasheet]	

	gpio->port_config |= PORT_CONFIG_PSC1;

	cdm->clk_enables |= PSC1_CLK_EN;

	cdm->mclken_div_psc1 	= 0x8010;

	rx_fifo = MPC52xx_PA(MPC52xx_PSCx_OFFSET(psc_num))+0x60;
	tx_fifo = MPC52xx_PA(MPC52xx_PSCx_OFFSET(psc_num))+0x80;


	spin_lock_init(&priv->dma_lock);

// 	printk("Before Tasks init\n");

	rx_bcom = bcom_gen_bd_rx_init(2, (phys_addr_t)rx_fifo, initiator_rx, BCOM_IPR_PSC1_RX, 512);

	tx_bcom = bcom_gen_bd_tx_init(8, (phys_addr_t)tx_fifo, initiator_tx, BCOM_IPR_PSC1_TX);


	r_irq = bcom_get_task_irq(rx_bcom);
	t_irq = bcom_get_task_irq(tx_bcom);

	printk("r_irq %d 0x%08x t_irq %d 0x%08x, r_tasknum %d, t_tasknum %d\n", r_irq, r_irq, t_irq, t_irq, rx_bcom->tasknum, tx_bcom->tasknum);
	psc->command = (MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
	psc->command = MPC52xx_PSC_RST_RX;
	psc->command = MPC52xx_PSC_RST_TX;
	psc->command = MPC52xx_PSC_RST_ERR_STAT;

	psc->op1 = 0x03;
	udelay(10);
	psc->op0 = 0x02;
	udelay(50);
	
	SICR = 0x0F90E000;
	
	psc->command 	= 0x0A;
	psc->sicr	= SICR;
	psc->ctur	= 0x03;
	psc->ctlr	= 0x34;
	psc->ccr	= 0x070F0000;

	psc->rfalarm	= RX_ALARM;		
	psc->tfalarm	= TX_ALARM;		
	psc->rfcntl	= RX_GRAN;		
	psc->tfcntl	= TX_GRAN;		
	psc->isr_imr.isr	= 0x00;
	psc->isr_imr.imr	= 0x00;	
	psc->mode	= 0x00;			/* set RX interrupt to RxRDY */
	psc->command = (MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);

	psc->tfdata = 0xF0010000; 	// Power-down [Table 1, MAX5712 Datasheet]
	udelay(100);	

	psc->tfdata = 0xF0000000; 	// Wake-up [Table 1, MAX5712 Datasheet]		

	udelay(100);
	
// 	printk("Before request_irq's\n");
	if (request_irq(r_irq, &SPI_rx_irq, /*IRQF_DISABLED*/0, "SPI rx dma", priv)) {
		printk(KERN_ERR "SPI: SDMA rx irq allocation failed\n");
		return;
	} 
	if (request_irq(t_irq, &SPI_tx_irq, /*IRQF_DISABLED*/0, "SPI tx dma", priv)) {
		printk(KERN_ERR "SPI: SDMA tx irq allocation failed\n");
		return;
	} 

	bcom_gen_bd_tx_reset(tx_bcom);
	bcom_gen_bd_rx_reset(rx_bcom);

// 	printk("Before submitting a buffer\n");
	spin_lock(&priv->dma_lock);
	while (!bcom_queue_full(tx_bcom)) {
		struct bcom_gen_bd *bd;

		/* Submit a new one */
		bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(tx_bcom);
		bd->status = PERIODSIZE_HW;
		bd->buf_pa = SPI_tx_silence.pa;
		bcom_submit_next_buffer(tx_bcom, NULL);;
	}
	spin_unlock(&priv->dma_lock);

	bd = bcom_prepare_next_buffer(rx_bcom);

	bd->status = 512;
	bd->data[0] = SPI_rx_bufs.pa;

	bcom_submit_next_buffer(rx_bcom, (void *)SPI_rx_bufs.pa);

	psc->command = MPC52xx_PSC_RST_RX;
	psc->command = MPC52xx_PSC_RST_TX;
	psc->command = MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE;


	bcom_enable(tx_bcom);
	bcom_enable(rx_bcom);

	kt_timeup   = timeval_to_ktime(tclockup);
	kt_timedown = timeval_to_ktime(tclockdown);
	hrtimer_init(&start_timer, CLOCK_REALTIME, HRTIMER_MODE_REL);	
	start_timer.function = timer_funct;
// 	printk("Before exit in Setup_SPI()\n");
}

void register_period_elapsed(void (*funcptr)()) {
/*	printk("Function registered\n");*/
	hook_per_elap = funcptr;
};

void register_hook_frames_rcv(UInteger32 (*funcptr)()) {
/*	printk("Function registered\n");*/
	hook_frames_rcv = funcptr;
	hrtimer_start(&start_timer, kt_timeup, HRTIMER_MODE_REL);
};

int snd_SPI_pcm_prepare(struct snd_pcm_substream * substream) {
#ifdef SND_I2S_DEBUG
	snd_pcm_runtime_t *runtime = substream->runtime;
	printk("snd_I2Smgt_pcm_prepare\n");
	printk("  runtime->buffer_size=%i\n",(int)runtime->buffer_size);
	printk("  runtime->period_size=%i\n",(int)runtime->period_size);
	printk("  runtime->periods=%i\n",(int)runtime->periods);
#endif
	SPI_play = SPI_pos = 0;
	return 0;
};

EXPORT_SYMBOL(register_period_elapsed);
EXPORT_SYMBOL(register_hook_frames_rcv);
EXPORT_SYMBOL(snd_SPI_pcm_prepare);


int SPIspeaker_init(void) {

	SPI_buffers_init();
	SPI_setup();
	return 0;
}

void SPIspeaker_exit(void) {

	/* Freeing buffer SPIspeaker */
	if (SPI_rx_bufs.va) {
	kfree(SPI_rx_bufs.va);
	}
	if (SPI_tx_silence.va) {
	kfree(SPI_tx_silence.va);
	}
}

module_init(SPIspeaker_init);
module_exit(SPIspeaker_exit);

MODULE_DESCRIPTION("MPC52xx SPI");
MODULE_AUTHOR("Pedro Domínguez,,,, (pedro.dominguez@aed-engineering.com)");
MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2008-03-14 14:21 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-03-03 12:08 I2S driver Angelo
2008-03-03 12:40 ` Roman Fietze
2008-03-03 13:47   ` Mark Brown
2008-03-03 13:05 ` Pedro Luis D. L.
2008-03-03 22:06   ` Wolfgang Denk
2008-03-03 16:42 ` Timur Tabi
  -- strict thread matches above, loose matches on Subject: below --
2008-03-03 13:18 i2s driver Angelo
2008-03-03 17:05 I2S driver Angelo
2008-03-03 17:14 ` Phillip Lougher
2008-03-03 20:50 ` Timur Tabi
2008-03-04 10:26 Angelo
2008-03-04 13:23 ` Pedro Luis D. L.
2008-03-04 16:38   ` Angelo
2008-03-05 10:09     ` Pedro Luis D. L.
2008-03-05 10:45       ` Angelo
2008-03-14 14:21   ` Angelo
2008-03-05 12:36 Pedro Luis D. L.
2008-03-06 10:27 ` Angelo
2008-03-06 13:41   ` Pedro Luis D. L.

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).