All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.