* SPI driver?
@ 2000-11-08 18:12 clark
2000-11-08 18:37 ` Tobias Otto-Adamczak
0 siblings, 1 reply; 11+ messages in thread
From: clark @ 2000-11-08 18:12 UTC (permalink / raw)
To: linuxppc-embedded
Hello,
I was wondering if anbody has a working SPI driver yet. I noticed one that
wasn't working yet was included in HHL 1.2 . Has anyone made any progress
on it since then? I also noticed it relied on CPM_IIC micro code patch
, does it have any known side effects?
Many thanks in advanced
Conn Clark
*****************************************************************
If you live at home long enough, your parrents will move out.
*****************************************************************
Conn Clark
Engineering Stooge clark@esteem.com
Electronic Systems Technology Inc. www.esteem.com
Stock Ticker Symbol ELST
"clark@esteem.com" Copyright 2000 all rights reserved. May not be sold or
used for advertisements.
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: SPI driver?
2000-11-08 18:12 clark
@ 2000-11-08 18:37 ` Tobias Otto-Adamczak
0 siblings, 0 replies; 11+ messages in thread
From: Tobias Otto-Adamczak @ 2000-11-08 18:37 UTC (permalink / raw)
To: clark; +Cc: linuxppc-embedded
> I was wondering if anbody has a working SPI driver yet.
I have no ready-to-use driver but a few functions (init, transfer,
disable) that I use successfully with my MBX.
> I also noticed it relied on CPM_IIC micro code patch,
My code works with or witout the patch; MBX uses SCC1 for Ethernet.
Ciao - Tobias
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: SPI driver?
@ 2000-11-08 21:18 Dan Winkler
0 siblings, 0 replies; 11+ messages in thread
From: Dan Winkler @ 2000-11-08 21:18 UTC (permalink / raw)
To: 'clark@esteem.com', linuxppc-embedded
I have a working SPI and I2C driver with and without the microcode patch
(I'm currently using it in slave mode but it can be easily modified to work
in master mode). I'll e-mail them after I clean them up a bit.
-Dan Winkler
-----Original Message-----
From: clark@esteem.com [mailto:clark@esteem.com]
Sent: Wednesday, November 08, 2000 1:13 PM
To: linuxppc-embedded@lists.linuxppc.org
Subject: SPI driver?
Hello,
I was wondering if anbody has a working SPI driver yet. I noticed
one that
wasn't working yet was included in HHL 1.2 . Has anyone made any progress
on it since then? I also noticed it relied on CPM_IIC micro code patch
, does it have any known side effects?
Many thanks in advanced
Conn Clark
*****************************************************************
If you live at home long enough, your parrents will move out.
*****************************************************************
Conn Clark
Engineering Stooge clark@esteem.com
Electronic Systems Technology Inc. www.esteem.com
Stock Ticker Symbol ELST
"clark@esteem.com" Copyright 2000 all rights reserved. May not be sold or
used for advertisements.
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* SPI driver?
@ 2001-12-18 0:48 Kevin Fry
2001-12-18 9:50 ` Alex Zeffertt
0 siblings, 1 reply; 11+ messages in thread
From: Kevin Fry @ 2001-12-18 0:48 UTC (permalink / raw)
To: linuxppc-embedded
Is there an MPC8260 SPI driver out there for Linux? It wouldn't be
terribly hard to write one on my own, but why re-invent the wheel?
A link to an 8xx driver would be almost as good. The only one I've found
so far has been SPI over a PC's parallel port. heh
Thanks
Kevin Fry
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: SPI driver?
@ 2001-12-18 0:58 Rod Boyce
2001-12-18 1:38 ` Kevin Fry
0 siblings, 1 reply; 11+ messages in thread
From: Rod Boyce @ 2001-12-18 0:58 UTC (permalink / raw)
To: 'Kevin Fry', linuxppc-embedded
Have you tried looking in the <kernel root>/arch/ppc/8xx_io directory there
is a file there called spi.c This believe it or not is a SPI driver in a
limited form for the 8XX powerpc cpu. The kernel I'm using is 2.2.14 from
ftp://ftp.denx.de <ftp://ftp.denx.de> this is a very good kernel I suggest
you look it over at least once.
Rod
-----Original Message-----
From: Kevin Fry [mailto:kevin@carts.com]
Sent: Tuesday, 18 December 2001 13:49
To: linuxppc-embedded@lists.linuxppc.org
Subject: SPI driver?
Is there an MPC8260 SPI driver out there for Linux? It
wouldn't be
terribly hard to write one on my own, but why re-invent the
wheel?
A link to an 8xx driver would be almost as good. The only
one I've found
so far has been SPI over a PC's parallel port. heh
Thanks
Kevin Fry
** Sent via the linuxppc-embedded mail list. See
http://lists.linuxppc.org/
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: SPI driver?
2001-12-18 0:58 Rod Boyce
@ 2001-12-18 1:38 ` Kevin Fry
0 siblings, 0 replies; 11+ messages in thread
From: Kevin Fry @ 2001-12-18 1:38 UTC (permalink / raw)
To: Rod Boyce; +Cc: linuxppc-embedded
Just got it and found the driver, gracias. I also got Denx's 2.4.4 kernel and
the SPI driver is missing. I assume this is because the microcode patches are
there and the spi driver doesn't work with them?
Is this the only 8xx or 8260 driver there is?? If there's more I'd like to see
them, just to keep my options open.
Thanks again Rod
Kevin
Rod Boyce wrote:
> Have you tried looking in the <kernel root>/arch/ppc/8xx_io directory there
> is a file there called spi.c This believe it or not is a SPI driver in a
> limited form for the 8XX powerpc cpu. The kernel I'm using is 2.2.14 from
> ftp://ftp.denx.de <ftp://ftp.denx.de> this is a very good kernel I suggest
> you look it over at least once.
>
> Rod
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: SPI driver?
2001-12-18 0:48 Kevin Fry
@ 2001-12-18 9:50 ` Alex Zeffertt
2001-12-18 10:54 ` Alex Zeffertt
0 siblings, 1 reply; 11+ messages in thread
From: Alex Zeffertt @ 2001-12-18 9:50 UTC (permalink / raw)
To: Kevin Fry, linuxppc-embedded
>
> A link to an 8xx driver would be almost as good. The only one I've found
> so far has been SPI over a PC's parallel port. heh
Kevin,
Here's one (below) for the 860. You'll probably need to change the GPIO pin used to select the SPI
slave. You may also want get rid of the semaphore ioctl call. I put this in as a way to allow
processes to do a sequence of reads/writes atomically. However, it also allows one process to
permanently lock out all others :-(
Alex
/*
MPC8xx CPM SPI interface.
Copyright (c) 2001 Navin Boppuri/Prashant Patel
(nboppuri@trinetcommunication.com/pmpatel@trinetcommunication.com)
This interface requires the microcode patches.
Helper functions for memdump put in by Ralph Nichols (ralphn@trinetcommunication.com)
Alex Zeffertt 06Sep01
Notes:
0.
This code drives the MPC860 SPI as a master device.
1.
The Chip selects are controlled by the ioctl interface.
This is necessary because some SPI devices lose state
information when the CS is unasserted.
For example, with an SPI EEPROM (e.g. AT25010) you may
have to assert the CS, send a READ command, receive
some data, and then unassert the CS. The corresponding
user commands are:
ioctl(s, SPI_IOCTL_RESET, 1); // 3rd argument selects port A pin 1
write(s, readcmdstring, sizeof(readcmdstring));
read(s, buffer, sizeof(buffer);
ioctl(s, SPI_IOCTL_SET, 1); // 3rd argument selects port A pin 1
For such a device we cannot assert the CS at the start of
write/read and unassert it at the end of write/read, because
it would forget what command it was processing.
Since all devices will differ in this respect we have left
the decision of when to assert the CS to the user.
2.
Several processes may have this device open at a time. However,
this may result in one process interferring with the other
process. To prevent this we have introduced a semaphore:
// To gain semaphore
ioctl(s, SPI_IOCTL_SEMAPHORE_DOWN, 0); // 3rd argument is unused
... do reads and writes and non-semaphore ioctls
// To release semaphore
ioctl(s, SPI_IOCTL_SEMAPHORE_UP, 0); // 3rd argument is unused
If every process uses these two ioctls before and after any device
operations, then every device operation will be atomic.
3.
This driver protects against simultaneous calls to read/write
by the use of wait queues.
4.
This driver uses interrupts to indicate when the TX buffer is sent
or the RX buffer is full.
*/
/*########################### Includes ###############################*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mpc8xx.h>
#include <asm/irq.h>
#include <asm/8xx_immap.h>
#include "commproc.h"
/*########################### Defines/typedefs ########################*/
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(format,args...) printk(format,##args)
#else
#define DPRINTK(format,args...)
#endif
/* This is the SPI device number, but I use the minors to indicate
* the SPI device address.
*/
#define CPM_SPI_CDEV_MAJOR 89
#define SPI_BUFFER_SIZE 64
typedef int SPI_IOCTL_FN(uint cmd, ulong arg);
typedef struct _spi_ioctl_cmds
{
char *name;
SPI_IOCTL_FN *fn;
} SPI_IOCTL_CMDS;
typedef enum _spi_ioctls
{
SPI_IOCTL_INIT,
SPI_IOCTL_RESET,
SPI_IOCTL_SET,
SPI_IOCTL_SEMAPHORE_UP,
SPI_IOCTL_SEMAPHORE_DOWN,
NUM_SPI_IOCTL_CMDS
} SPI_IOCTLS;
// number of bits in a character
#define CHAR_BITS 8
#define SPI_CLK_SPEED 500000 // Max = 2.1MHz (see data sheet) Minium = BRGCLK/1024
/*########################## Forward declarations #####################*/
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 *);
static void cpm_spi_interrupt(void *);
static int cpm_spi_ioctl(struct inode *, struct file *, uint, ulong);
static int t1_semaphore_down(uint cmd, ulong arg);
static int t1_semaphore_up(uint cmd, ulong arg);
static int t1_cs_set(uint cmd, ulong arg);
static int t1_cs_reset(uint cmd, ulong arg);
static int t1_cs_init(uint cmd, ulong arg);
int spi_ioctl_set_clk(uint cmd, ulong arg);
/*########################## File scope variables #####################*/
static SPI_IOCTL_CMDS spi_ioctl_cmds[NUM_SPI_IOCTL_CMDS] = {
{"Initialise CS", &t1_cs_init },
{"Reset CS", &t1_cs_reset},
{"Set CS", &t1_cs_set},
{"Semaphore UP", &t1_semaphore_up},
{"Semaphore DOWN", &t1_semaphore_down},
};
/* Number of users of the driver at any one time */
static int cpm_spi_users = 0;
DECLARE_WAIT_QUEUE_HEAD(waitq); // For waiting for SPI hardware to complete operation
DECLARE_WAIT_QUEUE_HEAD(lockq); // To prevent more than one user at a time in read() or write()
static int reading_writing = 0; // Set this when in read() or write()
static struct semaphore spi_sem; // set this in t1_semaphore_up, clear in t1_semaphore_down
static ushort t_tbase, r_rbase;
static volatile cbd_t *tbd, *rbd;
/* RX and TX buffers */
static ulong hostpage; /* points to page of host memory */
static pte_t pte_old; /* saves hostpage's Page Table Entry */
static unsigned char *rxbuffer; /* rx and tx buffers in hostpage */
static unsigned char *txbuffer;
static struct file_operations cpm_spi_fops = {
read: cpm_spi_read,
write: cpm_spi_write,
ioctl: cpm_spi_ioctl,
open: cpm_spi_open,
release: cpm_spi_close,
};
// Stuff initialised by cpm_spi_init()
static int two_char_times_us; // we need to wait 2 character times after tx interrupt to be sure
buf sent
static ushort spmode; // This is the value to write to spmode register on an open
static char *cpm_spi_drivername = "spi";
static uint cpm_spi_dp_addr;
/*########################## Function definitions #####################*/
static int t1_semaphore_down(uint cmd, ulong arg)
{
down_interruptible(&spi_sem);
return 0;
}
static int t1_semaphore_up(uint cmd, ulong arg)
{
up(&spi_sem);
return 0;
}
static int t1_cs_set(uint cmd, ulong arg)
{
volatile immap_t* immap = (immap_t*)IMAP_ADDR;
// write one to PAarg
immap->im_ioport.iop_padat |= (0x8000 >> arg);
return 0;
}
static int t1_cs_reset(uint cmd, ulong arg)
{
volatile immap_t* immap = (immap_t*)IMAP_ADDR;
// write zero to PAarg
immap->im_ioport.iop_padat &= ~(0x8000 >> arg);
return 0;
}
static int t1_cs_init(uint cmd, ulong arg)
{
volatile immap_t* immap = (immap_t*)IMAP_ADDR;
// Port A pin PAarg
// configured as actively driven
// General purpose output
// cpmp->cp_pbodr &= ~(0x0010); // pre mod rev A ICU
immap->im_ioport.iop_padir |= (0x8000 >> arg);
immap->im_ioport.iop_papar &= ~(0x8000 >> arg);
// Set line!
return t1_cs_set(cmd, arg);
}
static int cpm_spi_ioctl(struct inode *ip, struct file *fp, uint cmd, ulong arg)
{
// Is this a valid IOCTL cmd
if (cmd < NUM_SPI_IOCTL_CMDS) {
DPRINTK("Handling ioctl->%s\n", spi_ioctl_cmds[cmd].name);
// Yes so handle it
return (*(spi_ioctl_cmds[cmd].fn)) (cmd, arg);
}
// Invalid IOCTL command
return -ENOIOCTLCMD;
}
int __init cpm_spi_init(void)
{
volatile spi_t *spi;
volatile immap_t *immap;
volatile cpic8xx_t *cpi;
volatile sysconf8xx_t *sys;
volatile cpm8xx_t *cp;
bd_t* bd = (bd_t*)__res;
unsigned int system_clock = bd->bi_busfreq * 1000000;
unsigned int divisor = system_clock/SPI_CLK_SPEED;
int sys_clocks_per_spi_clock = 1;
pte_t *pte;
DPRINTK(__FUNCTION__ "\n");
// Work out what to write to SPMODE:
spmode =
//SPMODE_REV | // msb of character sent and recvd first // E1 device has lsb first
SPMODE_MASTER| // SPI is a master
SPMODE_EN | // enable device
((CHAR_BITS-1) << SPMODE_LEN_SHIFT); // Sets the number of bits in a character
// Work out how to set speed
if (divisor >= 16) {
spmode |= SPMODE_DIV16; // pre divide BRGCLK by 16
divisor = (divisor + 15)/16; // rounds down clockspeed
sys_clocks_per_spi_clock *= 16;
}
if (divisor > 64) {
printk("Error: (" __FUNCTION__ ") SPI_CLK_SPEED out of range\n");
return -EFAULT;
} else {
divisor = (divisor + 3)/4; // rounds down clockspeed
spmode |= (divisor-1) << SPMODE_PM_SHIFT;
sys_clocks_per_spi_clock *= (4*divisor);
}
// Calculate how many us 2 character times is (and round up for safety)
two_char_times_us = ((2*CHAR_BITS*sys_clocks_per_spi_clock) +
(bd->bi_busfreq-1))/bd->bi_busfreq; // round up
// Get internal registers
immap = (immap_t *)IMAP_ADDR;
//cpm interrupt controller
cpi = (cpic8xx_t*)&(immap->im_cpic);
//cpm interrupt controller
sys = (sysconf8xx_t*)&(immap->im_siu_conf);
// Get pointer to Communication Processor
cp = cpmp;
spi = (volatile spi_t *)&cp->cp_dparam[PROFF_SPI];
#if USE_IIC_PATCH // I2C patch also relocates SPI
// Check for SPI relocation patch
if ((reloc = spi->spi_rpbase)) {
spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
printk(" MICROCODE RELOCATION PATCH \n");
}
#endif
/* 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 = 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;
/* Allocate space for one transmit and one receive buffer
* descriptor in the DP ram.
*/
cpm_spi_dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 2);
// Set up the SPI parameters in the parameter ram.
spi->spi_rbase = r_rbase = cpm_spi_dp_addr;
spi->spi_tbase = t_tbase = cpm_spi_dp_addr + sizeof(cbd_t);
/***********IMPORTANT******************/
/* Setting transmit and receive buffer descriptor
pointers intially to rbase and rbase. Only the
microcode patches documentation talks about initializing
this pointer. This is missing from the sample I2C driver.
If you dont initialize these pointers, the kernel hangs. */
spi->spi_rbptr = r_rbase;
spi->spi_tbptr = t_tbase;
// Set to big endian
spi->spi_tfcr = SMC_EB;
spi->spi_rfcr = SMC_EB;
// Set maximum receive size
spi->spi_mrblr = SPI_BUFFER_SIZE;
// Setting CPCR (initialise rx and tx params)
cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI,CPM_CR_INIT_TRX) | CPM_CR_FLG;
// Wait for acknowledgement
while (cp->cp_cpcr & CPM_CR_FLG)
;
// sets SDMA configuration register
immap->im_siu_conf.sc_sdcr = 0x0001;
// clear all spi events
cp->cp_spie = 0xff;
// Clear SPI interrupt Mask (We only want interrupts when device is open)
cp->cp_spim = 0;
/* My PortB setting */
/* These setting may be different for you.
Refer example 16-443 MPC823 Manual*/
// Port B pin 31 configured as
// actively driven General purpose
// output
// Port B pins 28, 29, 30
// configured as SPIMISO, SPIMOSI,
// and SPICLK, respectively
cp->cp_pbodr &= ~0x000e;
cp->cp_pbodr |= 0x0001;
cp->cp_pbdir |= 0x000f;
cp->cp_pbpar &= ~0x0001;
cp->cp_pbpar |= 0x000e;
// Initialise PA1 and PA3 for output - these go to CLKXSRC on McBSB1
// and CS on E1 line driver, respectively
t1_cs_init(2, 1);
t1_cs_init(2, 3);
// tx and rx buffer descriptors
tbd = (volatile cbd_t *)&cp->cp_dpmem[t_tbase];
rbd = (volatile cbd_t *)&cp->cp_dpmem[r_rbase];
// Initialize tx and rx bd's (in particular
// clear the BD_SC_READY and BD_SC_EMPTY bits
memset((void*)tbd, 0, sizeof(cbd_t));
memset((void*)rbd, 0, sizeof(cbd_t));
// Allocate 1 page of host memory for the data
hostpage = __get_dma_pages(GFP_KERNEL,0 /*order*/);
pte = va_to_pte(hostpage);
// Save the current pte setting for the page
pte_val(pte_old) = pte_val(*pte);
// Disable cacheing for the page
pte_val(*pte) |= _PAGE_NO_CACHE;
// Make it clean
flush_tlb_page(current->mm->mmap, hostpage);
rxbuffer = (unsigned char *) hostpage;
txbuffer = rxbuffer + SPI_BUFFER_SIZE;
/* Set the bd's rx and tx buffer address pointers */
tbd->cbd_bufaddr = __pa(txbuffer);
rbd->cbd_bufaddr = __pa(rxbuffer);
/* install interrupt handler if using interrupts */
cpm_install_handler(CPMVEC_SPI, cpm_spi_interrupt, (void *)spi);
/* register spi device */
if (register_chrdev(CPM_SPI_CDEV_MAJOR,cpm_spi_drivername,&cpm_spi_fops))
printk("unable to get major %d for SPI devs\n",
CPM_SPI_CDEV_MAJOR);
printk("Successfully registered spi major=%d\n", CPM_SPI_CDEV_MAJOR);
/* initialise the semaphore for mutual exclusion */
sema_init(&spi_sem, 1);
return 0;
}
/* Open does not have to do much */
static int cpm_spi_open(struct inode *ip, struct file *fp)
{
DPRINTK(__FUNCTION__ "\n");
fp->f_op = &cpm_spi_fops;
/* Increment the number of users. */
if (cpm_spi_users++ == 0)
{
/* If this is the first user we need to initialise device */
/* Write to SPMODE */
cpmp->cp_spmode = spmode;
DPRINTK("cpmp->cp_spmode=%04x\n",cpmp->cp_spmode);
/* Set mask to allow all interrupts */
cpmp->cp_spim =
SPIE_MME|
SPIE_TXE|
SPIE_BSY|
SPIE_TXB|
SPIE_RXB;
}
return(0);
}
static int cpm_spi_close(struct inode *ip, struct file *fp)
{
DPRINTK(__FUNCTION__ "\n");
if (--cpm_spi_users == 0)
{
/* If no more users left shut down SPI. */
cpmp->cp_spmode = 0;
cpmp->cp_spie = 0xff;
cpmp->cp_spim = 0;
}
return(0);
}
/* write is exactly like read.
spi does read and write simultaneously */
static ssize_t cpm_spi_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
volatile immap_t *immap;
volatile cpic8xx_t *cpi;
volatile cpm8xx_t *cp;
// Cannot have 2 users sending or receiving at once
wait_event_interruptible(lockq,reading_writing == 0);
reading_writing = 1;
DPRINTK(__FUNCTION__ "\n");
// Make sure buffer is not greater than buffer size !
if (count > SPI_BUFFER_SIZE)
return -EINVAL;
// Get internal memory map
immap = (immap_t *)IMAP_ADDR;
// Get cpm interrupt controller
cpi = (cpic8xx_t*) &(immap->im_cpic);
// Get pointer to Communication Processor
cp = cpmp;
// Make sure BD is not in use !
if ((tbd->cbd_sc & BD_SC_READY) || (rbd->cbd_sc & BD_SC_EMPTY))
{
printk("Error: BD in use\n");
return -EFAULT;
}
// Set the tx bd status and data length
tbd->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_SC_INTRPT;
tbd->cbd_datlen = count;
// Set rx bd status and data length (=0 because we're not reading here)
rbd->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
rbd->cbd_datlen = 0;
// Copy transmit data from user space to tx buffer */
if (copy_from_user((void*)txbuffer,(void*)buf, count))
{
printk("Error: copying from user\n");
return -EFAULT;
}
// Start spi transfer
cp->cp_spcom |= 0x80;
// Wait for transfer to complete
wait_event_interruptible(waitq, (tbd->cbd_sc & BD_SC_READY) == 0 && (rbd->cbd_sc & BD_SC_EMPTY)
== 0);
DPRINTK("txsc=%04x/rxsc=%04x\n", tbd->cbd_sc, rbd->cbd_sc);
// Wait two char times like the book says
udelay(two_char_times_us);
// Allow another user to send or receive
reading_writing = 0;
wake_up_interruptible(&lockq);
return count;
}
/* read is exactly like write.
spi does read and write simultaneously.
It's not exactly simultaneous. I've noticed that transmit is done
first and then receive.*/
static ssize_t cpm_spi_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
volatile immap_t *immap;
volatile cpic8xx_t *cpi;
volatile cpm8xx_t *cp;
// Cannot have 2 users sending or receiving at once
wait_event_interruptible(lockq,reading_writing == 0);
reading_writing = 1;
DPRINTK(__FUNCTION__ "\n");
// Make sure buffer is not greater than buffer size !
if (count > SPI_BUFFER_SIZE)
{
return -EINVAL;
}
//printk("Count is %d\n", count);
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
cpi = (cpic8xx_t*)&(immap->im_cpic); //cpm interrupt controller
cp = cpmp; /* Get pointer to Communication Processor */
// check BDs are not in use!
if ((tbd->cbd_sc & BD_SC_READY) || (rbd->cbd_sc & BD_SC_EMPTY))
{
printk("Error: BD in use\n");
return -EFAULT;
}
/* Initialize buffer memory to empty */
memset((void*)txbuffer, 0, count);
// Setting tx bd status and data length
tbd->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_SC_INTRPT;
tbd->cbd_datlen = count; /* We write count 0 s and hope device ignores it */
// Setting rx bd status and data length
rbd->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
rbd->cbd_datlen = count;
// Start spi transfer
cp->cp_spcom |= 0x80;
// Wait for transfer to complete
wait_event_interruptible(waitq, (tbd->cbd_sc & BD_SC_READY) == 0 && (rbd->cbd_sc & BD_SC_EMPTY)
== 0);
DPRINTK("txsc=%04x/rxsc=%04x\n", tbd->cbd_sc, rbd->cbd_sc);
// Wait two char times like the book says
udelay(two_char_times_us);
// Transfer is done.
//printk("Reception: ");
//memdump((void*)rxbuffer, count);/* dump of rxbuffer after transmit */
/* copy received bytes to user space */
/***********
* Please note that the data in rxbuffer is in big endian format.
* you will have to flip it.
*************/
copy_to_user((void*)buf, (void*)rxbuffer, count);
// Allow another user to send or receive
reading_writing = 0;
wake_up_interruptible(&lockq);
return count;
}
/* Interrupt handler in case you use spi interrupts. I have tried using the interrupts
and they work just fine. You can use his handler to detect */
static void cpm_spi_interrupt(void *dev_id)
{
unsigned char events = cpmp->cp_spie;
DPRINTK("Spi event reg. 0x%x\n", events);
/* reset spi event register and mode */
cpmp->cp_spie = events;
if (SPIE_MME & events)
printk ("Error: ~SPISEL asserted externally while SPI in master mode\n");
if (SPIE_TXE & events)
printk("Error: Tx error\n");
if (SPIE_BSY & events)
printk("Error: No Rx buffer available\n");
if (SPIE_TXB & events)
wake_up_interruptible(&waitq);
if (SPIE_RXB & events)
wake_up_interruptible(&waitq);
}
/********************************************************
* module_init() is called by insmod, if built as module,
* or by do_initcalls(), if built as a resident driver.
********************************************************/
module_init(cpm_spi_init);
#ifdef MODULE
static void __exit cpm_spi_exit(void)
{
volatile cpm8xx_t *cp = cpmp;
pte_t *pte;
// Only allow this is no user has device open
// This should be automatically true.
// (This means we're not going to get any interrupts while doing rmmod.)
if (cpm_spi_users != 0)
printk(__FILE__ " " __FUNCTION__ " line %d: This should not happen\n", __LINE__);
// unregister the driver majore number
if (unregister_chrdev(CPM_SPI_CDEV_MAJOR, cpm_spi_drivername) < 0)
printk(__FILE__ " " __FUNCTION__ " line %d: This should not happen\n", __LINE__);
// uninstall cpm interrupt handler
cpm_free_handler(CPMVEC_SPI);
// Hand back page containing rxbuffer and txbuffer
pte = va_to_pte(hostpage);
pte_val(*pte) = pte_val(pte_old);
// Make it clean
flush_tlb_page(current->mm->mmap, hostpage);
// Free the page
free_pages(hostpage, 0 /*order*/);
// Reinitialise cs's back to old state
t1_cs_init(2, 3);
t1_cs_init(2, 1);
// Reinitialise Port B
cp->cp_pbpar &= ~0x000f;
cp->cp_pbdir |= 0x000f;
cp->cp_pbdat |= 0x000f;
// Free the memory allocated to cpm_spi_dp_addr
m8xx_cpm_dpfree(cpm_spi_dp_addr);
}
module_exit(cpm_spi_exit);
#endif // MODULE
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: SPI driver?
2001-12-18 9:50 ` Alex Zeffertt
@ 2001-12-18 10:54 ` Alex Zeffertt
0 siblings, 0 replies; 11+ messages in thread
From: Alex Zeffertt @ 2001-12-18 10:54 UTC (permalink / raw)
To: Kevin Fry, linuxppc-embedded
Alex Zeffertt wrote:
>
> >
> > A link to an 8xx driver would be almost as good. The only one I've found
> > so far has been SPI over a PC's parallel port. heh
>
Kevin,
Sorry, I forgot to add that you need to make the following mods to arch/ppc/8xx_io/commproc.h
Alex
diff -u linux-2.4.4-2001-11-24/arch/ppc/8xx_io/commproc.h
linux-2.4.4-2001-11-24.new/arch/ppc/8xx_io/commproc.h
--- linux-2.4.4-2001-11-24/arch/ppc/8xx_io/commproc.h Mon Sep 10 16:29:33
2001 +++
linux-2.4.4-2001-11-24.new/arch/ppc/8xx_io/commproc.h Fri Dec 7 11:54:58 2001
@@ -37,6 +37,7 @@
#define CPM_CR_RESTART_TX ((ushort)0x0006)
#define CPM_CR_SET_GADDR ((ushort)0x0008)
#define CPM_CR_SET_TIMER CPM_CR_SET_GADDR
+#define CPM_CR_CLOSE_RX_BD ((ushort)0x0007)
/* Channel numbers.
*/
@@ -93,7 +94,9 @@
#define BD_SC_PR ((ushort)0x0008) /* Parity error */
#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */
#define BD_SC_OV ((ushort)0x0002) /* Overrun */
+#define BD_SC_UN ((ushort)0x0002) /* Underrun */
#define BD_SC_CD ((ushort)0x0001) /* ?? */
+#define BD_SC_CL ((ushort)0x0001) /* Collision */
/* Parameter RAM offsets.
*/
@@ -704,7 +707,11 @@
#define SICR_ENET_MASK ((uint)0x0000ff00)
#define SICR_ENET_CLKRT ((uint)0x00003E00)
-#undef USE_IIC_PATCH /* We need the I²C µCode Patch */
+#ifdef CONFIG_UCODE_PATCH
+# define USE_IIC_PATCH
+#else
+# undef USE_IIC_PATCH /* We need the I²C µCode Patch */
+#endif
#endif /* CONFIG_LWMON */
@@ -962,6 +969,16 @@
#define SPMODE_EN ((ushort)0x0100) /* Enable */
#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */
#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */
+#define SPMODE_MASTER ((ushort)0x0200) /* Am SPI master */
+#define SPMODE_LEN_SHIFT 4 /* shift of character length field */
+#define SPMODE_PM_SHIFT 0 /* shift of Prescale Modulus field */
+
+/* SPIE fields */
+#define SPIE_MME 0x20
+#define SPIE_TXE 0x10
+#define SPIE_BSY 0x04
+#define SPIE_TXB 0x02
+#define SPIE_RXB 0x01
/* CPM interrupts. There are nearly 32 interrupts generated by CPM
* channels or devices. All of these are presented to the PPC core
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 11+ messages in thread
* SPI driver?
@ 2007-09-10 16:16 Hesam Kohanteb
2007-09-11 15:50 ` Nicholas Hickman
0 siblings, 1 reply; 11+ messages in thread
From: Hesam Kohanteb @ 2007-09-10 16:16 UTC (permalink / raw)
To: linuxppc-embedded
We need a Linux based SPI driver for MPC885. Do you know where can I
possibly find the code.
Regards. --Hesam
--
Hesam Yehuda Kohanteb
(Netra Systems & Networking),
M/S USCA12-216 4120 Network Circle
Santa Clara, CA 95054
(W) 408-276-7329 X17329, Fax 408-276-4552
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: SPI driver?
2007-09-10 16:16 SPI driver? Hesam Kohanteb
@ 2007-09-11 15:50 ` Nicholas Hickman
2007-09-11 20:19 ` Wolfgang Denk
0 siblings, 1 reply; 11+ messages in thread
From: Nicholas Hickman @ 2007-09-11 15:50 UTC (permalink / raw)
To: Hesam.Kohanteb, linuxppc-embedded
I am also in search of this, or some information about one. Please let
me know if you find anything.
I ran across an existing platform that used an mpc8270. During boot up
it displayed:
[ 17.828513] SPIDriver: module license 'Proprietary' taints kernel.
[ 17.865052] CPM SPI Driver: $Revision: 1.0 $ wd@denx.de
I have been all over denx and have not been able to find it. This
particular system used the SPI for a DSP chip.=20
-Nick
-----Original Message-----
From: linuxppc-embedded-bounces+nhickman=3Ddtechlabs.com@ozlabs.org
[mailto:linuxppc-embedded-bounces+nhickman=3Ddtechlabs.com@ozlabs.org] =
On
Behalf Of Hesam Kohanteb
Sent: Monday, September 10, 2007 12:17 PM
To: linuxppc-embedded@ozlabs.org
Subject: SPI driver?
We need a Linux based SPI driver for MPC885. Do you know where can I
possibly find the code.
Regards. --Hesam
--
Hesam Yehuda Kohanteb
(Netra Systems & Networking),
M/S USCA12-216 4120 Network Circle
Santa Clara, CA 95054
(W) 408-276-7329 X17329, Fax 408-276-4552
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: SPI driver?
2007-09-11 15:50 ` Nicholas Hickman
@ 2007-09-11 20:19 ` Wolfgang Denk
0 siblings, 0 replies; 11+ messages in thread
From: Wolfgang Denk @ 2007-09-11 20:19 UTC (permalink / raw)
To: Nicholas Hickman; +Cc: Hesam.Kohanteb, linuxppc-embedded
In message <8140AAF341CC904BA92C3D6A5A1909782F0D4F@ditech-1.ditechllc.com> you wrote:
> I am also in search of this, or some information about one. Please let
> me know if you find anything.
>
> I ran across an existing platform that used an mpc8270. During boot up
> it displayed:
> [ 17.828513] SPIDriver: module license 'Proprietary' taints kernel.
> [ 17.865052] CPM SPI Driver: $Revision: 1.0 $ wd@denx.de
>
> I have been all over denx and have not been able to find it. This
> particular system used the SPI for a DSP chip.
Probably somebody copied and modified a driver they found in our
trees. We release all such code under GPL...
You can find SPI driver code in our old linuxppc_2_4_devel tree, but
this does not include support for MPC82xx; and then there is an
ancient (5+ years) 82xx SPI driver in our linux-2.4 (2.4.4) kernel
tree.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Thought for the day: What if there were no hypothetical situations?
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2007-09-11 20:19 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-10 16:16 SPI driver? Hesam Kohanteb
2007-09-11 15:50 ` Nicholas Hickman
2007-09-11 20:19 ` Wolfgang Denk
-- strict thread matches above, loose matches on Subject: below --
2001-12-18 0:58 Rod Boyce
2001-12-18 1:38 ` Kevin Fry
2001-12-18 0:48 Kevin Fry
2001-12-18 9:50 ` Alex Zeffertt
2001-12-18 10:54 ` Alex Zeffertt
2000-11-08 21:18 Dan Winkler
2000-11-08 18:12 clark
2000-11-08 18:37 ` Tobias Otto-Adamczak
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).