* Re: SPI driver
@ 2003-06-26 5:35 Yigit Can
0 siblings, 0 replies; 3+ messages in thread
From: Yigit Can @ 2003-06-26 5:35 UTC (permalink / raw)
To: kernelnewbies, linux c programming
[-- Attachment #1: Type: text/plain, Size: 742 bytes --]
sorry my mistake the code is attached now.
the spmode register is in loopback mode to test the driver.
the problem is when we set the rx_buffer_desc. to 0xb000 it does not return
to empty state after the writing has finished.
the writing part is working (I can see it from oscilloscope)
thanks
----- Original Message -----
From: "Yigit Can" <yigit.can@karel.com.tr>
To: "linux c programming" <linux-c-programming@vger.kernel.org>
Sent: Wednesday, June 25, 2003 5:29 PM
Subject: SPI driver
>
> Hello,
>
> I'm trying to write an SPI driver for 850_ppc kernel
>
> I have written some code according to the datasheet and some samples.
>
> I can send data but I am not able to receive any data
>
> any comments ?
>
> Thank you
>
> Yigit
>
[-- Attachment #2: cpm_spi.c --]
[-- Type: application/octet-stream, Size: 9769 bytes --]
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>
#include <linux/wrapper.h>
#include "commproc.h"
//#include "cpm_spi.h"
#define DRIVER_NAME "cmp_spi"
MODULE_AUTHOR("YIGIT CAN");
MODULE_DESCRIPTION("SPI driver");
#undef DEBUG
#define CPM_SPI_MAJOR 89
#define CONFIG_CPM_SPI_BDSIZE 16
static immap_t *immap = NULL;
static cpm8xx_t *cpmp = NULL;
static unsigned int dp_addr;
static ushort t_tbase, r_rbase;
static volatile cbd_t *tx_bdf, *rx_bdf;
static u_char *tx_buf, *rx_buf;
static int cpm_spi_open(struct inode *inode, struct file *fp);
static int cpm_spi_release(struct inode *inode, struct file *fp);
static ssize_t cpm_spi_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
static ssize_t cpm_spi_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
static int cpm_spi_init(void);
static void cpm_spi_cleanup(void);
/*
* File operations supported by this driver.
*/
struct file_operations cpm_spi_fops = {
open: cpm_spi_open,
release: cpm_spi_release,
write: cpm_spi_write,
read: cpm_spi_read,
};
static int cpm_spi_open ( struct inode *inode, struct file *fp )
{
fp->f_op = &cpm_spi_fops;
MOD_INC_USE_COUNT;
return 0;
}
static int cpm_spi_release( struct inode *inode, struct file *fp )
{
MOD_DEC_USE_COUNT;
return 0;
}
static ssize_t cpm_spi_read( struct file *fp, char *buf, size_t count, loff_t *f_pos )
{
volatile cpm8xx_t *cp; // comm proc pointer
unsigned int i;
if ( count > CONFIG_CPM_SPI_BDSIZE ) // if the length of data is greater than buffer size print error
{
printk( "SPI : Invalid Size\n" );
return -EINVAL;
}
cp = cpmp; // pointer to the comm proc
/* if ( rx_bdf->cbd_sc & BD_SC_EMPTY ) // if buffer is in use exit with error
{
printk( "SPI : Buffer Descriptor is in use\n" );
return -EFAULT;
}
*/
memset( ( void* )tx_buf, 0, count ); // empty tx_buf ( fill with 0 s )
tx_bdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
tx_bdf->cbd_datlen = count;
rx_bdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; // receive reg statuses
rx_bdf->cbd_datlen = count; // data length
// start SPI transfer
cp->cp_spcom |= 0x80; // start transfer
for ( i=0 ;i<100000; i++) // 10000 us wait to complete transfer
{
udelay( 1 );
// if ( (rx_bdf->cbd_sc & BD_SC_EMPTY) == 0 ) // this bit turns to 0 when the transfer completes
if ( (tx_bdf->cbd_sc & BD_SC_READY) == 0 ) // this bit turns to 0 when the transfer completes
break;
}
if ( i == 100000 ) // is data received in 10000 us period ?
{
printk ( "SPI : Transfer Timeout\n" );
return -EIO;
}
copy_to_user( ( void* )buf, ( void* )rx_buf, count );
printk ("\nSONUC : %d ",*rx_buf);
return count;
}
static ssize_t cpm_spi_write( struct file *fp, const char *buf, size_t count, loff_t *f_pos )
{
volatile cpm8xx_t *cp; // comm proc pointer
unsigned long int i;
unsigned long flags;
// save_flags(flags); cli () ;
if ( count > CONFIG_CPM_SPI_BDSIZE ) // if the length of data is greater than buffer size print error
{
printk( "SPI : Invalid Size\n" );
return -EINVAL;
}
cp = cpmp; // pointer to the comm proc
/* if ( ( tx_bdf->cbd_sc & BD_SC_READY ) || ( rx_bdf->cbd_sc & BD_SC_EMPTY ) ) // if buffer is in use exit with error
{
printk( "SPI : Buffer Descriptor is in use\n" );
return -EFAULT;
}
*/
tx_bdf->cbd_sc = 0xB800; // trans. reg statuses
tx_bdf->cbd_datlen = count; // data length
rx_bdf->cbd_sc = 0xB000;
rx_bdf->cbd_datlen = count;
if ( copy_from_user( (void *)tx_buf,(void *) buf, count ) )
{
printk ( "SPI : Error copying from user space\n" );
return -EFAULT;
}
// start SPI transfer
printk ( "SPI : Before transfer regs : rx_bdf->cbd_sc = %08x : tx_bdf->cbd_sc = %08x \n",rx_bdf->cbd_sc, tx_bdf->cbd_sc );
printk ( "SPI : Before transfer regs : rx_bdf->datlen = %08x : tx_bdf->datlen = %08x \n",rx_bdf->cbd_datlen, tx_bdf->cbd_datlen );
cp->cp_spcom |= 0x80; // start transfer
for ( i=0; i<1000000; i++) // 10000 us wait to complete transfer
{
udelay( 1 );
if ( (tx_bdf->cbd_sc & BD_SC_READY) == 0 ) // this bit turns to 0 when the transfer completes
break;
}
if ( i == 1000000 ) // is data sent in 10000 us period ?
{
printk ( "SPI : Transfer Timeout : rx_bdf->cdb_sc = %08x : tx_bdf->cbd_sc = %08x \n",rx_bdf->cbd_sc, tx_bdf->cbd_sc );
return -EIO;
}
printk ("RECEIVED : %d ", *rx_buf);
// restore_flags(flags);
return count;
}
static int cpm_spi_init(void)
{
int err = 0; // error variable
volatile spi_t *spi; // spi type pointer
volatile cpic8xx_t *cpi;
// unsigned long imtemp;
printk (KERN_INFO "CPM SPI Driver by Yigit Can\n"); // print driver info
/* Global pointer to internal registers */
/* if ( !cpmp )
{
asm( "mfspr %0,638": "=r"(imtemp) : );
imtemp &= 0xFFFF0000;
immap = (immap_t *)&imtemp;
}
*/
immap = ( immap_t * )IMAP_ADDR; // pointer to immr reg
cpi = ( cpic8xx_t *)&(immap->im_cpic);
if ( !immap ) // if immr can not be found print error and exit
{
printk ( "\n Unable to locate immr\n ");
return -1;
}
cpmp = ( cpm8xx_t * ) &( immap->im_cpm ); // pointer to comm proc
// printk (" CPMP ");
spi = ( spi_t * ) &cpmp->cp_dparam[ PROFF_SPI ]; // pointer to spi
// if IIC microcode patched to the kernel use relocated rpbase
#ifdef USE_IIC_PATCH
if ( spi->spi_rpbase )
{
spi = ( spi_t * ) &cpmp->cp_dpmem[ spi->spi_rpbase ];
printk ( "SPI : Using IIC patch\n" );
}
#endif
spi->spi_rstate = 0;
spi->spi_rdp = 0;
spi->spi_rbptr = 0;
spi->spi_rbc = 0;
spi->spi_rxtmp = 0;
spi->spi_tstate = 0;
spi->spi_tdp = 0;
spi->spi_tbptr = 0;
spi->spi_tbc = 0;
spi->spi_txtmp = 0;
/*
* Initiliaze port pins for SPI
* par dir odr
* PB28 -> SPIMISO: 1 1 0
* PB29 -> SPIMOSI: 1 1 0
* PB30 -> SPICLK : 1 1 0
*/
cpmp->cp_pbodr &= ~(0x000e);
cpmp->cp_pbdir |= 0x000e;
cpmp->cp_pbpar |= 0x000e; // these pins configured as in the datasheet
dp_addr = m8xx_cpm_dpalloc( sizeof( cbd_t ) * 2 ); //buffer malloc in dp ram
if ( dp_addr == CPM_DP_NOSPACE )
{
printk( "cpm_spi: m8xx_cpm_dpalloc() failed\n" );
return -ENOMEM;
}
spi->spi_rbase = r_rbase = dp_addr; // first part of buffer is receive base
spi->spi_tbase = t_tbase = dp_addr + sizeof( cbd_t ); // sec part is transmit
spi->spi_rbptr = r_rbase; //start addr of rec buffer is receive buf pointer
spi->spi_tbptr = t_tbase; // start addr of trans buf is transmit buf pointer
// cpmp->cp_cpcr |=0x0051; // as mentioned in the data sheet
cpmp->cp_cpcr |= mk_cr_cmd( CPM_CR_CH_SPI, CPM_CR_INIT_TRX ) | CPM_CR_FLG;
while(cpmp->cp_cpcr & CPM_CR_FLG) ; // if the command completed
// printk ("\n COMM PROC COMMAND COMPLETED \n");
immap->im_siu_conf.sc_sdcr = 0x0001;
// Set to big endian
spi->spi_tfcr = 0x10;
spi->spi_rfcr = 0x10;
// Set maximum receive size
spi->spi_mrblr = 0x0010; // max receive buf size
/* Clear all pending SPI events and mask all possible SPI
interrupts. For the moment we don't use interrupts.
*/
cpmp->cp_spie = 0xff;
cpmp->cp_spim = 0x00;
cpmp->cp_spmode = 0x4370;
// cpmp->cp_spmode = 0x0370 | SPMODE_LOOP; // spi mode reg as mentioned in the data sheet
/*
I will PUT OTHER PORT INIT STRINGS HERE !
*/
/* Tx and Rx buffer descriptors. */
tx_bdf = ( volatile cbd_t * )&cpmp->cp_dpmem[ t_tbase ];
rx_bdf = ( volatile cbd_t * )&cpmp->cp_dpmem[ r_rbase ];
printk ( "\nADRESSES : tx_bdf = %d, rx_bdf = %d ",tx_bdf,rx_bdf);
/* Initialize Tx and Tx BD's */
// rx_bdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
// tx_bdf->cbd_sc = BD_SC_LAST | BD_SC_WRAP;
memset( (void*)tx_bdf, 0, sizeof(cbd_t) );
memset( (void*)rx_bdf, 0, sizeof(cbd_t) );
/* Allocate memory for Rx and Tx buffers */
rx_buf = ( u_char * )m8xx_cpm_hostalloc( CONFIG_CPM_SPI_BDSIZE );
tx_buf = ( u_char * )m8xx_cpm_hostalloc( CONFIG_CPM_SPI_BDSIZE );
if ( rx_buf == NULL || tx_buf == NULL )
{
printk ( "SPI : Error getting memory for rx_buf" );
return -ENOMEM;
}
/* Set the bd's rx and tx buffer address pointers */
tx_bdf->cbd_bufaddr = __pa( tx_buf );
rx_bdf->cbd_bufaddr = __pa( rx_buf );
printk ( "\nBUFADDR ADRESSES (cbd_bufaddr): tx_bdf = %d, rx_bdf = %d ",tx_bdf->cbd_bufaddr,rx_bdf->cbd_bufaddr);
/*
* Finally register the driver.
*/
err = register_chrdev( CPM_SPI_MAJOR, DRIVER_NAME, &cpm_spi_fops );
if ( err < 0 ) {
printk( "\ncpm_spi: Couldn't register driver ( major=%d )\n", CPM_SPI_MAJOR );
return err;
}
else
printk ("SPI DEVICE REGISTERED\n");
return 0;
}
static void cpm_spi_cleanup( void )
{
unregister_chrdev( CPM_SPI_MAJOR, DRIVER_NAME );
m8xx_cpm_dpfree( dp_addr );
}
module_init(cpm_spi_init);
module_exit(cpm_spi_cleanup);
^ permalink raw reply [flat|nested] 3+ messages in thread* SPI driver
@ 2003-06-25 14:29 Yigit Can
2003-06-25 16:27 ` Jan-Benedict Glaw
0 siblings, 1 reply; 3+ messages in thread
From: Yigit Can @ 2003-06-25 14:29 UTC (permalink / raw)
To: linux c programming, linux kernel
Hello,
I'm trying to write an SPI driver for 850_ppc kernel
I have written some code according to the datasheet and some samples.
I can send data but I am not able to receive any data
any comments ?
Thank you
Yigit
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2003-06-26 5:35 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-06-26 5:35 SPI driver Yigit Can
-- strict thread matches above, loose matches on Subject: below --
2003-06-25 14:29 Yigit Can
2003-06-25 16:27 ` Jan-Benedict Glaw
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).