* SPI driver
@ 2002-04-24 11:37 LEROY Christophe
2002-04-24 11:50 ` Alex Zeffertt
0 siblings, 1 reply; 5+ messages in thread
From: LEROY Christophe @ 2002-04-24 11:37 UTC (permalink / raw)
To: liste ppc embedded
Hi, I'm looking for an SPI driver for the PPC (MPC860), but the address
given on the HOWTO (ftp://216.118.31.75/pub/) doesn't work.
Where can I find it ?
Thanks
Christophe
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: SPI driver
@ 2002-04-24 15:23 Navin Boppuri
0 siblings, 0 replies; 5+ messages in thread
From: Navin Boppuri @ 2002-04-24 15:23 UTC (permalink / raw)
To: LEROY Christophe, liste ppc embedded
[-- Attachment #1: Type: text/plain, Size: 589 bytes --]
I've sent these files before to the list. Do a search on them for some instructions. But should compile and work as a loadable module.
Navin.
-----Original Message-----
From: LEROY Christophe [mailto:christophe.leroy@c-s.fr]
Sent: Wednesday, April 24, 2002 6:38 AM
To: liste ppc embedded
Subject: SPI driver
Hi, I'm looking for an SPI driver for the PPC (MPC860), but the address
given on the HOWTO (ftp://216.118.31.75/pub/) doesn't work.
Where can I find it ?
Thanks
Christophe
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
[-- Attachment #2: spi.c --]
[-- Type: application/octet-stream, Size: 13313 bytes --]
/*
* (C) Copyright 2000
* Navin Boppuri/Prashant Patel @ Trinet Communications Inc.
*
* 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
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/mpc8xx.h>
#include <asm/8xx_immap.h>
#include "commproc.h"
#include "spi.h"
#define SPI_DEBUG 1 /* Debugging needs */
/* fops routines for the spi driver
*/
static int
cpm_spi_open(struct inode *, struct file *);
static int
cpm_spi_close(struct inode *, struct file *);
static ssize_t
cpm_spi_write(struct file *,const char *, size_t, loff_t *);
static ssize_t
cpm_spi_read(struct file *,char *, size_t, loff_t *);
/* fops data structure is used to interface the driver to the Linux Kernel
*/
static struct
file_operations cpm_spi_fops = {
owner: THIS_MODULE,
read: cpm_spi_read,
write: cpm_spi_write,
open: cpm_spi_open,
release: cpm_spi_close
};
/* spi device data structure
*/
typedef struct spi_dev_t{
/* pointers to rx and tx buffer descriptors
*/
cbd_t *tbdf, *rbdf;
/* Receive and trasnmit buffer descriptors
* base addresses
*/
ushort r_tbase, r_rbase;
/* spi receive buffer
*/
unsigned char rbuf[CPM_SPI_MRBLR];
/* spi receive buffer length
*/
unsigned int rlen;
/* spi transmit buffer
*/
unsigned char tbuf[CPM_SPI_MRBLR];
}spi_dev_t;
/* module related stuff
*/
#ifdef MODULE
/* Module entry points for insmod and rmmod, etc
*/
extern int init_module(void);
extern int cleanup_module(void);
/* Called locally by cleanup_module().
*/
static int __init cpm_spi_init(void);
#else
/* Called directly by kernel init code.
*/
extern int __init cpm_spi_init(void);
#endif
/* Used by cleanup_modules
*/
static int __exit cpm_spi_cleanup(void);
/* end of module related stuff
*/
/* Only one user at a time
*/
static int cpm_spi_flags = CPM_SPI_CLOSE;
/* pointer to spi device data
*/
static spi_dev_t *spi_dev;
/* Helper functions to peek into tx and rx buffers
*/
#ifdef SPI_DEBUG
char quickhex(int i)
{
if(i >= 10 ) return i - 10 + 'A';
return i + '0';
}
int quickisprint(int c)
{
if( c >= 'A' && c <= 'Z' ) return 1;
if( c >= 'a' && c <= 'z' ) return 1;
if( c >= '0' && c <= '9' ) return 1;
return 0;
}
void memdump(void *pv, int num)
{
int i;
unsigned char* pc = (unsigned char*)pv;
for(i = 0; i < num; i++ )
printk("%c%c ", quickhex(pc[i] >> 4), quickhex(pc[i] & 0x0f));
printk("\t");
for(i = 0; i < num; i++ )
printk("%c", quickisprint(pc[i]) ? pc[i] : '.');
printk("\n");
}
#endif /* SPI_DEBUG */
/* init routine called when the driver module is loaded
*/
int __init
cpm_spi_init(void)
{
uint dp_addr;
volatile spi_t *spi;
volatile immap_t *immap;
volatile sysconf8xx_t *sys;
volatile cpm8xx_t *cp;
/* pointer to internal registers
*/
immap = (immap_t *)IMAP_ADDR;
/* pointer to system interface unit
*/
sys = (sysconf8xx_t*)&(((immap_t*)IMAP_ADDR)->im_siu_conf);
/* Get pointer to Communication Processor
*/
cp = (cpm8xx_t*)&(((immap_t*)IMAP_ADDR)->im_cpm);
/* pointer to spi parameter ram
*/
spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
/* Allocate memory for private data
*/
spi_dev = (spi_dev_t*)kmalloc(sizeof(spi_dev_t),GFP_ATOMIC);
/* Initialize the parameter ram.
*/
/* We need to make sure many things are initialized to zero,
* especially in the case of a microcode patch.
*/
spi->spi_rstate = CPM_SPI_PARAM_INIT;
spi->spi_rdp = CPM_SPI_PARAM_INIT;
spi->spi_rbptr = CPM_SPI_PARAM_INIT;
spi->spi_rbc = CPM_SPI_PARAM_INIT;
spi->spi_rxtmp = CPM_SPI_PARAM_INIT;
spi->spi_tstate = CPM_SPI_PARAM_INIT;
spi->spi_tdp = CPM_SPI_PARAM_INIT;
spi->spi_tbptr = CPM_SPI_PARAM_INIT;
spi->spi_tbc = CPM_SPI_PARAM_INIT;
spi->spi_txtmp = CPM_SPI_PARAM_INIT;
/* Allocate space for one transmit and one receive buffer
* descriptor in the DP ram.
*/
dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 2);
/* Set up the IIC parameters in the parameter ram.
*/
spi->spi_rbase = spi_dev->r_rbase = dp_addr;
spi->spi_tbase = spi_dev->r_tbase = dp_addr + sizeof(cbd_t);
spi->spi_rbptr = spi->spi_rbase;
spi->spi_tbptr = spi->spi_tbase;
/* Set to big endian.
*/
spi->spi_tfcr = SMC_EB;
spi->spi_rfcr = SMC_EB;
/* Set maximum receive size.
*/
spi->spi_mrblr = CPM_SPI_MRBLR;
/* Initialize Tx/Rx parameters.
*/
cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
/* Configuring Port B to enable SPIMISO, SPIMOSI and SPICLK
*/
cp->cp_pbpar |= CPM_PORTB_SPICLK | CPM_PORTB_SPIMOSI | CPM_PORTB_SPIMISO;
cp->cp_pbdir |= CPM_PORTB_SPICLK | CPM_PORTB_SPIMOSI | CPM_PORTB_SPIMISO;
cp->cp_pbodr &= ~(CPM_PORTB_SPICLK | CPM_PORTB_SPIMOSI | CPM_PORTB_SPIMISO);
/* tx and rx buffer descriptors
*/
spi_dev->tbdf = (cbd_t *)&cp->cp_dpmem[spi_dev->r_tbase];
spi_dev->rbdf = (cbd_t *)&cp->cp_dpmem[spi_dev->r_rbase];
/* initialize tx and rx bd status to not ready and not empty respectively
*/
spi_dev->tbdf->cbd_sc &= ~BD_SC_READY;
spi_dev->rbdf->cbd_sc &= ~BD_SC_EMPTY;
/* register spi device
*/
if (register_chrdev(CPM_SPI_MAJOR,CPM_SPI_CHRDEV,&cpm_spi_fops))
{
printk (KERN_WARNING CPM_SPI_CHRDEV "_init: unable to get major %d\n", CPM_SPI_MAJOR);
return -EIO;
}
printk(KERN_INFO SPI_VERSION "spi0: device registered successfully\n");
return 0; /* Success */
}
/*
* Open does not have to do much, just make sure only one user.
*/
static int
cpm_spi_open(struct inode *ip, struct file *fp)
{
/* We allow only one user of the device.
*/
if (cpm_spi_flags & CPM_SPI_OPEN)
return(EBUSY);
/* pointer to the fops data structure
*/
fp->f_op = &cpm_spi_fops;
/* lock acess to the driver
*/
cpm_spi_flags |= CPM_SPI_OPEN;
#ifdef MODULE
/* increment module use count
*/
MOD_INC_USE_COUNT;
#endif
return(0);
}
/* Close the driver
*/
static int
cpm_spi_close(struct inode *ip, struct file *fp)
{
volatile immap_t *immap;
volatile cpm8xx_t *cp;
/* pointer to internal registers
*/
immap = (immap_t *)IMAP_ADDR;
/* Get pointer to Communication Processor
*/
cp = (cpm8xx_t*)&(((immap_t*)IMAP_ADDR)->im_cpm);
/* Shut down SPI.
*/
cp->cp_spmode = SPI_SPMODE_CLEAR;
cp->cp_spie = SPI_CLEAR_EVENTS;
cp->cp_spim = SPI_MASK_EVENTS;
/* release the driver
*/
cpm_spi_flags &= ~CPM_SPI_OPEN;
#ifdef MODULE
MOD_DEC_USE_COUNT; /* Decrement module use count */
#endif
return(0);
}
/*
* spi write function. spi data transfer is a simultaneous operation.
* Both write and read operations are carried out as one io operation.
*/
static ssize_t
cpm_spi_write(struct file *file,const char *buf, size_t count, loff_t *ppos)
{
volatile immap_t *immap;
volatile cpm8xx_t *cp;
volatile iop8xx_t *iop;
int tloop = 0; /* timout variable for spi transfer */
/* pointer to internal registers
*/
immap = (immap_t *)IMAP_ADDR;
/* pointer to io ports
*/
iop = (iop8xx_t*)&(((immap_t*)IMAP_ADDR)->im_ioport);
/* pointer to the communications processor
*/
cp = (cpm8xx_t*)&(((immap_t*)IMAP_ADDR)->im_cpm);
/* Initialize buffer memory to empty
*/
memset((void*)spi_dev->tbuf,CPM_SPI_BUFFER_INIT,CPM_SPI_MRBLR);
memset((void*)spi_dev->rbuf,CPM_SPI_BUFFER_INIT,CPM_SPI_MRBLR);
/* Copy the buffer data from user space to kernel space
*/
copy_from_user((void*)spi_dev->tbuf,(const void*)buf,(unsigned long)count);
#ifdef SPI_DEBUG
printk("TX DUMP: ");memdump((void*)spi_dev->tbuf,count);/* dump of txbuffer before transmit */
printk("RX DUMP: ");memdump((void*)spi_dev->rbuf,count);/* dump of rxbuffer before transmit */
#endif
/*Setting tx bd status and data length
*/
spi_dev->tbdf->cbd_bufaddr = __pa(spi_dev->tbuf);
spi_dev->tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
spi_dev->tbdf->cbd_datlen = count;
/*Setting rx bd status and data length
*/
spi_dev->rbdf->cbd_bufaddr = __pa(spi_dev->rbuf);
spi_dev->rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
spi_dev->rbdf->cbd_datlen = 0; /* set by the controller on receiving the data */
#ifdef SPI_DEBUG
printk("spi_dev->tbdf: 0x%x spi_dev->tbdf->cbd_bufaddr: 0x%x spi_dev->tbdf->cbd_sc:
0x%x spi_dev->tbdf->cbd_datlen: 0x%x \n",spi_dev->tbdf,(uint)spi_dev->tbdf->cbd_bufaddr,
(ushort)spi_dev->tbdf->cbd_sc,(ushort)spi_dev->tbdf->cbd_datlen);
printk("spi_dev->rbdf: 0x%x spi_dev->rbdf->cbd_bufaddr: 0x%x spi_dev->rbdf->cbd_sc:
0x%x spi_dev->rbdf->cbd_datlen: 0x%x \n",spi_dev->rbdf,(uint)spi_dev->rbdf->cbd_bufaddr,
(ushort)spi_dev->rbdf->cbd_sc,(ushort)spi_dev->rbdf->cbd_datlen);
#endif
/* flush data cache so that CPM receives valid data
*/
flush_dcache_range((unsigned long)spi_dev->tbuf, (unsigned long) (spi_dev->tbuf + count));
flush_dcache_range((unsigned long)spi_dev->rbuf, (unsigned long) (spi_dev->rbuf + count));
/* spi mode setting
*/
cp->cp_spmode = SPI_SPMODE_DIV16 | SPI_SPMODE_REV | SPI_SPMODE_MASTER |
SPI_SPMODE_ENABLE | SPI_SPMODE_LEN_8 | SPI_SPMODE_PM_64;
/* Clear all interrupts! We use polling!
*/
cp->cp_spie = SPI_CLEAR_EVENTS; /*clear all spi events*/
cp->cp_spim = SPI_MASK_EVENTS; /*mask all SPI events*/
/* start spi transfer
*/
cp->cp_spcom |= SPI_SPCOM_STR | SPI_SPCOM_RESERVED;
/* Need this delay, otherwise hangs!
* Delay not calculated exactly.
*/
udelay(SPI_MYSTERY_DELAY);
/* wait till transfer is done. interrupts can be used instead.
* set spi_dev->tbdf->cbd_sc and spi_dev->rbdf->cb_sc to include BD_SC_INTRPT for interrupts.
* Timeout on transfer failure.
*/
while( ((spi_dev->tbdf->cbd_sc & BD_SC_READY) && (spi_dev->rbdf->cbd_sc & BD_SC_EMPTY)) || tloop++ > TOUT_LOOP);
/* update spi data pointer with the correct data length received
*/
spi_dev->rlen = spi_dev->rbdf->cbd_datlen;
#ifdef SPI_DEBUG
printk("TX DUMP : ");memdump((void*)spi_dev->tbuf,count);/* dump of txbuffer before transmit */
printk("RX DUMP : ");memdump((void*)spi_dev->rbuf,count);/* dump of rxbuffer before transmit */
#endif
#ifdef SPI_DEBUG
printk("spi_dev->tbdf: 0x%x spi_dev->tbdf->cbd_bufaddr: 0x%x spi_dev->tbdf->cbd_sc:
0x%x spi_dev->tbdf->cbd_datlen: 0x%x \n",spi_dev->tbdf,(uint)spi_dev->tbdf->cbd_bufaddr,
(ushort)spi_dev->tbdf->cbd_sc,(ushort)spi_dev->tbdf->cbd_datlen);
printk("spi_dev->rbdf: 0x%x spi_dev->rbdf->cbd_bufaddr: 0x%x spi_dev->rbdf->cbd_sc:
0x%x spi_dev->rbdf->cbd_datlen: 0x%x \n",spi_dev->rbdf,(uint)spi_dev->rbdf->cbd_bufaddr,
(ushort)spi_dev->rbdf->cbd_sc,(ushort)spi_dev->rbdf->cbd_datlen);
#endif
return count; /* return the number of bytes written */
}
/* spi read only returns data received during previous data transfer
*/
static ssize_t
cpm_spi_read(struct file *file,char *buf, size_t count, loff_t *ppos)
{
#ifdef SPI_DEBUG
memdump((void*)spi_dev->rbuf,spi_dev->rlen);
#endif
/* return data received during previous spi data transfer
*/
copy_to_user((void*)buf,(const void*)spi_dev->rbuf,spi_dev->rlen);
return spi_dev->rlen; /* return the number of bytes received during spi data transfer */
}
/* unregister the driver and clean up
*/
int __exit cpm_spi_cleanup(void)
{
int res;
/* Free private data memory
*/
kfree(spi_dev);
if ((res = unregister_chrdev (CPM_SPI_MAJOR,CPM_SPI_CHRDEV)))
{
printk(KERN_WARNING CPM_SPI_CHRDEV "_cleanup: unable to release major %d\n",
CPM_SPI_MAJOR);
return res;
}
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Navin Boppuri");
MODULE_DESCRIPTION("MPC8xx SPI Driver");
/* Called when module is loaded. Initializes the spi driver stuff
*/
int
init_module(void)
{
return cpm_spi_init();
}
/* Called when the module is removed.
*/
int
cleanup_module(void)
{
return cpm_spi_cleanup();
}
#endif
[-- Attachment #3: spi.h --]
[-- Type: application/octet-stream, Size: 2226 bytes --]
/*
*testing
* (C) Copyright 2000
* Navin Boppuri/Prashant Patel @ Trinet Communications Inc.
*
* 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
*/
#ifndef _PPC_SPI_8XX_H
#define _PPC_SPI_8XX_H
/* SPI init defines
*/
#define SPI_VERSION "spi: Service Processor SPI driver ver. 1.1"
#define CPM_SPI_CHRDEV "spi"
#define CPM_SPI_BUFFER_INIT 0
#define CPM_SPI_PARAM_INIT 0
#define CPM_SPI_MRBLR 128 /* Maximum receive buffer size for SPI */
#define CPM_SPI_MAJOR 81 /* SPI device major number */
#define SPI_MYSTERY_DELAY 1000
/* SPI SPMODE Register
*/
#define SPI_SPMODE_LOOP ((ushort)0x4000)
#define SPI_SPMODE_CI ((ushort)0x2000)
#define SPI_SPMODE_CP ((ushort)0x1000)
#define SPI_SPMODE_DIV16 ((ushort)0x0800)
#define SPI_SPMODE_REV ((ushort)0x0400)
#define SPI_SPMODE_MASTER ((ushort)0x0200)
#define SPI_SPMODE_SLAVE ((ushort)0x0200)
#define SPI_SPMODE_ENABLE ((ushort)0x0100)
#define SPI_SPMODE_LEN_8 ((ushort)0x0070)
#define SPI_SPMODE_PM_64 ((ushort)0x000f)
#define SPI_SPMODE_CLEAR ((ushort)0x0000)
/* SPI SPCOM Register
*/
#define SPI_SPCOM_STR ((unsigned char)0x80)
#define SPI_SPCOM_RESERVED ((unsigned char)0x00)
/* SPI Interrupt values
*/
#define SPI_CLEAR_EVENTS 0xff
#define SPI_MASK_EVENTS 0x00
/* Timeout loop count for SPI transfers
*/
#define TOUT_LOOP 5000000
/* PORT B Settings for SPI
*/
#define CPM_PORTB_SPICLK ((ulong)0x0002)
#define CPM_PORTB_SPIMOSI ((ulong)0x0004)
#define CPM_PORTB_SPIMISO ((ulong)0x0008)
/* Handle driver access
*/
#define CPM_SPI_CLOSE 0x00
#define CPM_SPI_OPEN 0x01
#endif
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: SPI Driver
@ 2002-03-13 23:09 Jeremy Rosen
0 siblings, 0 replies; 5+ messages in thread
From: Jeremy Rosen @ 2002-03-13 23:09 UTC (permalink / raw)
To: linuxppc-embedded, boppuri_navin
I plan to,
but right now it is too incomplete for release. ( no support for
multiple SPI device, no multithreading protection etc...)
moreover, I am working with a development board which has no SPI
device, so it has been tested only in loopback mode (the real board
we're developing should be available soon. )
just leave me a couple of weeks to work on it, and I'll send it to
everyone...
>>> sdfg sdfg <boppuri_navin@yahoo.com> 03/14/02 09:55am >>>
Hello Jeremy,
Would you be nice enough to put those drivers on some
site and send that link to everyone on the mailing
list? Thanks.
Navin.
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* SPI Driver
@ 2001-05-08 16:38 Navin Boppuri
0 siblings, 0 replies; 5+ messages in thread
From: Navin Boppuri @ 2001-05-08 16:38 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 328 bytes --]
Hello everyone,
The SPI driver link in LinuxPPC Embedded HOWTO by Graham is broken since
I had to kill my server machine. I will put it on some other server in a
few days. Meanwhile, if someone needs a copy, I will be glad to send it
to them. I am sending a copy with this mail too. Thanks.
<<spi.tar>>
Navin Boppuri
[-- Attachment #2: spi.tar --]
[-- Type: application/x-tar, Size: 20480 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2002-04-24 15:23 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-04-24 11:37 SPI driver LEROY Christophe
2002-04-24 11:50 ` Alex Zeffertt
-- strict thread matches above, loose matches on Subject: below --
2002-04-24 15:23 Navin Boppuri
2002-03-13 23:09 SPI Driver Jeremy Rosen
2001-05-08 16:38 Navin Boppuri
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).