From: Bharathi K [mailto:[email protected]]
Sent: Monday, October 24, 2011 10:48 AM
To: BHARATHI KANDIMALLA
Subject: spi driver
I am trying to develop spi driver for mpc885 processor
I am able to write to the device , but in master mode when I am trying to
read from the device We are getting segmentation fault,As it is master we
are generating the clock by dummy write
If I am trying to write using memset ,I am not getting any segmentation
fault.
I think it is the alignment problem
I am attaching the code we are using
Please give me the suggestion
Regards
Bharathi
#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/slab.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 <asm/cpm1.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/stddef.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_i2c.h>
#include <sysdev/fsl_soc.h>
#include <asm/cpm.h>
#include <asm/fs_pd.h>
/* Function code bits.
*/
#define SMC_EB ((u_char)0x10) /* Set big endian byte order */
#define CPM_MAXBD 1
#define CPM_MAX_READ 513
#define CORE_SPEED 50000000
#define SPI_BAUD 1750000
#define SPI_PM_VALUE ((CORE_SPEED/(4*SPI_BAUD)) - 1)
#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0))
#define I2COM_START 0x80
#define I2COM_MASTER 0x01
#define I2CER_TXE 0x10
#define I2CER_BUSY 0x04
#define I2CER_TXB 0x02
#define I2CER_RXB 0x01
#define I2MOD_EN 0x01
#define MPC885_SPI_MAJOR 120
/* SPI parameter RAM.
*/
struct spi_ram {
ushort rbase; /* Rx Buffer descriptor base address */
ushort tbase; /* Tx Buffer descriptor base address */
u_char rfcr; /* Rx function code */
u_char tfcr; /* Tx function code */
ushort mrblr; /* Max receive buffer length */
uint rstate; /* Internal */
uint rdp; /* Internal */
ushort rbptr; /* Internal */
ushort rbc; /* Internal */
uint rxtmp; /* Internal */
uint tstate; /* Internal */
uint tdp; /* Internal */
ushort tbptr; /* Internal */
ushort tbc; /* Internal */
uint txtmp; /* Internal */
uint res;
ushort rpbase; /* Relocation pointer */
ushort res2;
};
/* SPI Registers */
struct spi_reg {
u16 spmod;
u8 res1[4];
u8 spie;
u8 res2[3];
u8 spim;
u8 res3[2];
u8 spcom;
u8 res4[4];
};
struct cpm_spi {
struct of_device *ofdev;
uint dp_addr;
int version; /* CPM1=1, CPM2=2 */
int irq;
int cp_command;
int freq;
struct spi_reg __iomem *spi_reg;
struct spi_ram __iomem *spi_ram;
u16 spi_addr;
wait_queue_head_t spi_wait;
cbd_t __iomem *tbase;
cbd_t __iomem *rbase;
u_char *txbuf[CPM_MAXBD];
u_char *rxbuf[CPM_MAXBD];
u32 txdma[CPM_MAXBD];
u32 rxdma[CPM_MAXBD];
};
static struct cpm_spi *cpm;
static irqreturn_t mpc885_spi_interrupt(int irq, void *dev_id)
{
struct spi_reg __iomem *spi_reg = cpm->spi_reg;
unsigned int i,j;
unsigned char buf[20];
cbd_t __iomem *rbdf;
rbdf = cpm->rbase;
printk("\n mpc885_spi_interrupt ");
/* Clear interrupt. */
i = in_8(&spi_reg->spie);
printk("\n mpc885_spi_interrupt: status = %x", i);
out_8(&spi_reg->spie, i);
wake_up(&cpm->spi_wait);
printk("\n in int after wakeup");
out_8(&spi_reg->spie, i);
/* if (!(in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY)) {
i = in_be16(&rbdf->cbd_datlen);
memcpy(buf, cpm->rxbuf[0], i);
printk("\nspi rcv bytes :");
for (j = 0; j < i; j++) printk ("%x ", buf[j]);
}
*/
return IRQ_HANDLED;
}
static void mpc885_spi_force_close(void)
{
struct spi_reg __iomem *spi_reg = cpm->spi_reg;
printk("in spi mpc885_spi_force_close\n");
cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
out_8(&spi_reg->spim, 0x00); /* Disable all interrupts */
out_8(&spi_reg->spie, 0xff);
}
static void cpm_spi_parse_message(struct i2c_msg *pmsg, int num, int tx, int rx)
{
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
u_char *tb;
u_char *rb;
printk ("\nin spi parse message\n");
tx = rx = 0;
tbdf = cpm->tbase + tx;
rbdf = cpm->rbase + rx;
tb = cpm->txbuf[tx];
rb = cpm->rxbuf[rx];
/* Align read buffer */
rb = (u_char *) (((ulong) rb + 1) & ~1);
out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
out_be16(&tbdf->cbd_sc, 0);
if (!(pmsg->flags & I2C_M_NOSTART))
setbits16(&tbdf->cbd_sc, BD_I2C_START);
if (tx + 1 == num)
setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
// if (pmsg->flags & I2C_M_RD) {
/*
* To read, we need an empty buffer of the proper length.
* All that is used is the first byte for address, the remainder
* is just used for timing (and doesn't really have to exist).
*/
out_be16(&rbdf->cbd_datlen, 0);
out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
if (rx + 1 == CPM_MAXBD)
setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
eieio();
setbits16(&tbdf->cbd_sc, BD_SC_READY);
// } else {
if (!(pmsg->flags & I2C_M_RD)) {
memcpy(tb + 1, pmsg->buf, pmsg->len);
eieio();
setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
}
}
static int cpm_spi_check_message(struct i2c_msg *pmsg, int tx, int rx)
{
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
u_char *tb;
u_char *rb;
printk ("\nin spi check message\n");
tx = rx = 0;
tbdf = cpm->tbase + tx;
rbdf = cpm->rbase + rx;
tb = cpm->txbuf[tx];
rb = cpm->rxbuf[rx];
/* Align read buffer */
rb = (u_char *) (((uint) rb + 1) & ~1);
eieio();
if (pmsg->flags & I2C_M_RD) {
if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
printk("I2C read; No ack\n");
return -ENXIO;
}
if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
printk("I2C read; complete but rbuf empty\n");
return -EREMOTEIO;
}
if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
printk("I2C read; Overrun\n");
return -EREMOTEIO;
}
memcpy(pmsg->buf, rb, pmsg->len);
} else {
if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
printk("I2C write; No ack\n");
return -ENXIO;
}
if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
printk("I2C write; Underrun\n");
return -EIO;
}
if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
printk("I2C write; Underrun\n");
return -EIO;
}
if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
printk("I2C write; Collision\n");
return -EIO;
}
}
return 0;
}
static int mpc885_spi_xfer(struct i2c_msg *msgs, int num)
{
struct spi_reg __iomem *spi_reg = cpm->spi_reg;
struct spi_ram __iomem *spi_ram = cpm->spi_ram;
struct i2c_msg *pmsg;
int ret = 0, i;
int tptr;
int rptr;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
u_char *rb;
printk ("\nin spi_xfer\n");
if (num > CPM_MAXBD)
return -EINVAL;
/* Check if we have any oversized READ requests */
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
if (pmsg->len >= CPM_MAX_READ)
return -EINVAL;
}
/* Reset to use first buffer */
out_be16(&spi_ram->rbptr, in_be16(&spi_ram->rbase));
out_be16(&spi_ram->tbptr, in_be16(&spi_ram->tbase));
tbdf = cpm->tbase;
rbdf = cpm->rbase;
tptr = 0;
rptr = 0;
if (msgs->flags & I2C_M_RD) {
/*
* We go twice through the buffer descs
*/
while (i < (CPM_MAXBD * 2)) {
if (!(in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY)) {
// printk("\ndata found");
rb = cpm->rxbuf[rptr];
ret = in_be16(&rbdf->cbd_datlen);
memcpy(msgs->buf, rb, ret);
// printk("%s\n", pmsg->buf);
if (rptr >= CPM_MAXBD)
rptr = 0;
else
rptr++;
/*
* To read, we need an empty buffer of the
proper length.
* All that is used is the first byte for
address, the remainder
* is just used for timing (and doesn't really
have to exist).
*/
out_be16(&rbdf->cbd_datlen, 0);
out_be16(&rbdf->cbd_sc, BD_SC_EMPTY |
BD_SC_INTRPT);
if (rptr + 1 == CPM_MAXBD)
setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
break;
}
rptr++;
if (rptr >= CPM_MAXBD)
rptr = 0;
rbdf = cpm->rbase + rptr;
i++;
}
return ret;
}
while (tptr < num) {
pmsg = &msgs[tptr];
cpm_spi_parse_message(pmsg, num, tptr, rptr);
if (pmsg->flags & I2C_M_RD)
rptr++;
tptr++;
}
/* Start transfer now */
/* Enable RX/TX/Error interupts */
out_8(&spi_reg->spim, I2CER_TXE | I2CER_TXB | I2CER_RXB);
out_8(&spi_reg->spie, 0xff); /* Clear interrupt status */
out_be16(&spi_reg->spmod, 0x3770 | SPI_PM_VALUE ); //enabling spi
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) | 0x0100 );
//enabling spi
/* Begin transmission */
out_8(&spi_reg->spcom, 0x80);
tptr = 0;
rptr = 0;
while (tptr < num) {
/* Check for outstanding messages */
pmsg = &msgs[tptr];
if (pmsg->flags & I2C_M_RD)
ret = wait_event_timeout(cpm->spi_wait,
(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) ||
!(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
1 * HZ);
else
ret = wait_event_timeout(cpm->spi_wait,
!(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
1 * HZ);
if (ret == 0) {
ret = -EREMOTEIO;
goto out_err;
}
if (ret > 0) {
ret = cpm_spi_check_message(pmsg, tptr, rptr);
tptr++;
if (pmsg->flags & I2C_M_RD)
rptr++;
if (ret)
goto out_err;
}
}
#ifdef I2C_CHIP_ERRATA
/*
* Chip errata, clear enable. This is not needed on rev D4 CPUs.
* Disabling I2C too early may cause too short stop condition
*/
udelay(4);
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) & 0xfeff );
//disabling spi
#endif
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) & 0xfdff );
//configuring as slave
return (num);
out_err:
mpc885_spi_force_close();
#ifdef I2C_CHIP_ERRATA
/*
* Chip errata, clear enable. This is not needed on rev D4 CPUs.
*/
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) & 0xfeff );
//disabling spi
#endif
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) & 0xfdff );
//configuring as slave
return ret;
}
static void mpc885_reset_spi_params(struct cpm_spi *cpm)
{
struct spi_ram __iomem *spi_ram = cpm->spi_ram;
printk ("\nreset spi params\n");
/* Set up the SPI parameters in the parameter ram. */
out_be16(&spi_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
out_be16(&spi_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
if (cpm->version == 1) {
out_8(&spi_ram->tfcr, SMC_EB);
out_8(&spi_ram->rfcr, SMC_EB);
}
out_be16(&spi_ram->mrblr, CPM_MAX_READ);
out_be32(&spi_ram->rstate, 0);
out_be32(&spi_ram->rdp, 0);
out_be16(&spi_ram->rbptr, 0);
out_be16(&spi_ram->rbc, 0);
out_be32(&spi_ram->rxtmp, 0);
out_be32(&spi_ram->tstate, 0);
out_be32(&spi_ram->tdp, 0);
out_be16(&spi_ram->tbptr, 0);
out_be16(&spi_ram->tbc, 0);
out_be32(&spi_ram->txtmp, 0);
}
static int __devinit mpc885_spi_setup(struct cpm_spi *cpm)
{
struct of_device *ofdev = cpm->ofdev;
const u32 *data;
int len, ret, i;
void __iomem *spi_base;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
cpm8xx_t __iomem *pa_reg = immr_map(im_cpm);
printk ("\nSPI: setup\n");
init_waitqueue_head(&cpm->spi_wait);
cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL);
printk("SPI: irq no %d\n",cpm->irq);
if (cpm->irq == NO_IRQ)
{
printk("SPI: irq invalid\n");
return -EINVAL;
}
/* Install interrupt handler. */
ret = request_irq(cpm->irq, mpc885_spi_interrupt, IRQF_DISABLED,
"mpc885_spi",
cpm);
if(ret)
{
printk("SPI:request_irq invalid\n");
return ret;
}
/* SPI parameter RAM */
spi_base = of_iomap(ofdev->node, 1); // request_mem_region
if (spi_base == NULL) {
printk("SPI: of_iomap invalid\n");
ret = -EINVAL;
goto out_irq;
}
if (of_device_is_compatible(ofdev->node, "fsl,mpc885-spi")) {
/* Check for and use a microcode relocation patch. */
printk("SPI:of_device_is_compatible\n");
cpm->spi_ram = spi_base;
cpm->spi_addr = in_be16(&cpm->spi_ram->rpbase);
/*
* Maybe should use cpm_muram_alloc instead of hardcoding
* this in micropatch.c
*/
if (cpm->spi_addr) {
printk("SPI:of_device_is_compatible spi_addr\n");
cpm->spi_ram = spi_base;
cpm->spi_ram = cpm_muram_addr(cpm->spi_addr);
iounmap(spi_base);
}
cpm->version = 1;
} else {
printk("SPI:of_device_is_compatible spi_addr invalid\n ");
cpm->spi_ram = spi_base;
iounmap(spi_base);
ret = -EINVAL;
goto out_irq;
}
/* SPI control/status registers */
cpm->spi_reg = of_iomap(ofdev->node, 0);
if (cpm->spi_reg == NULL) {
ret = -EINVAL;
goto out_ram;
}
data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
if (!data || len != 4) {
printk("SPI:of_get_property fsl,cpm_command\n ");
ret = -EINVAL;
goto out_reg;
}
cpm->cp_command = *data;
printk("SPI: fsl,cpm_command %d\n",cpm->cp_command );
data = of_get_property(ofdev->node, "clock-frequency", &len);
if (data && len == 4)
{
cpm->freq = *data;
printk("SPI: clockfreq %d\n",cpm->freq );
}
else
// cpm->freq = 60000; /* use 60kHz i2c clock by default */
cpm->freq = SPI_BAUD; /* use 60kHz i2c clock by default */
printk("SPI: clockfreq %d\n",cpm->freq );
/*
* Allocate space for CPM_MAXBD transmit and receive buffer
* descriptors in the DP ram.
*/
cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
if (!cpm->dp_addr) {
printk("SPI: invalid dp_addr\n" );
ret = -ENOMEM;
goto out_reg;
}
cpm->tbase = cpm_muram_addr(cpm->dp_addr);
cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
/* Allocate TX and RX buffers */
tbdf = cpm->tbase;
rbdf = cpm->rbase;
for (i = 0; i < CPM_MAXBD; i++) {
cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
CPM_MAX_READ + 1,
&cpm->rxdma[i], GFP_KERNEL);
if (!cpm->rxbuf[i]) {
ret = -ENOMEM;
goto out_muram;
}
out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
out_be16(&rbdf[i].cbd_datlen, 0);
out_be16(&rbdf[i].cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
if (i + 1 == CPM_MAXBD)
setbits16(&rbdf[i].cbd_sc, BD_SC_WRAP);
eieio();
cpm->txbuf[i] = (unsigned char
*)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i],
GFP_KERNEL);
if (!cpm->txbuf[i]) {
ret = -ENOMEM;
goto out_muram;
}
out_be16(&tbdf[i].cbd_datlen, 0);
out_be16(&tbdf[i].cbd_sc, 0);
out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
printk("\ncbd_bufaddr in init =
%p",in_be32(&tbdf[i].cbd_bufaddr));
}
/* Initialize Tx/Rx parameters. */
mpc885_reset_spi_params(cpm);
dev_dbg(&cpm->ofdev->dev, "spi_ram 0x%p, spi_addr 0x%04x, freq
%d\n",
cpm->spi_ram, cpm->spi_addr, cpm->freq);
dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
(u8 __iomem *)cpm->tbase - DPRAM_BASE,
(u8 __iomem *)cpm->rbase - DPRAM_BASE);
cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
/*
* PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
* i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
* the actual i2c bus frequency.
*/
out_be32(&pa_reg->cp_pbdir, (in_be32(&pa_reg->cp_pbdir)) | 0x0006 );
//spi
out_be32(&pa_reg->cp_pbpar, (in_be32(&pa_reg->cp_pbpar)) | 0x000e
);//miso i/p
// pc13 cs hip select dsp
/* out_be16(&cpm->spi_reg->spmod, 0);
out_8(&cpm->spi_reg->spie, 0xff);
out_8(&cpm->spi_reg->spim, 0);*/
// out_8(&cpm->spi_reg->spcom, 0xff);
out_8(&cpm->spi_reg->spim,I2CER_TXE | I2CER_TXB | I2CER_RXB);
out_8(&cpm->spi_reg->spie, 0xff); /* Clear interrupt status */
out_be16(&cpm->spi_reg->spmod, 0x3770 | SPI_PM_VALUE ); //enabling spi
out_be16(&cpm->spi_reg->spmod, (in_be16(&cpm->spi_reg->spmod)) | 0x0100
); //enabling spi
return 0;
out_muram:
for (i = 0; i < CPM_MAXBD; i++) {
if (cpm->rxbuf[i])
dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
cpm->rxbuf[i], cpm->rxdma[i]);
if (cpm->txbuf[i])
dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
cpm->txbuf[i], cpm->txdma[i]);
}
cpm_muram_free(cpm->dp_addr);
out_reg:
iounmap(cpm->spi_reg);
out_ram:
if ((cpm->version == 1) && (!cpm->spi_addr))
iounmap(cpm->spi_ram);
out_irq:
free_irq(cpm->irq, cpm);
return ret;
}
static void mpc885_spi_shutdown(struct cpm_spi *cpm)
{
int i;
struct spi_reg __iomem *spi_reg = cpm->spi_reg;
printk ("\nspi shutdown\n");
/* Shut down SPI. */
out_be16(&spi_reg->spmod, (in_be16(&spi_reg->spmod)) & 0xfeff );
//disabling spi
out_8(&spi_reg->spim, 0x00); /* Disable all interrupts */
out_8(&spi_reg->spie, 0xff);
free_irq(cpm->irq, cpm);
/* Free all memory */
for (i = 0; i < CPM_MAXBD; i++) {
dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
cpm->rxbuf[i], cpm->rxdma[i]);
dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
cpm->txbuf[i], cpm->txdma[i]);
}
cpm_muram_free(cpm->dp_addr);
iounmap(cpm->spi_reg);
if ((cpm->version == 1) && (!cpm->spi_addr))
iounmap(cpm->spi_ram);
}
static int spi_open (struct inode *inode, struct file *filep)
{
return 0;
}
static ssize_t spi_read (struct file *filep, char __user *buf,
size_t count, loff_t *off)
{
int ret =0,i;
unsigned char *rxptr;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
struct spi_ram __iomem *spi_ram = cpm->spi_ram;
iop8xx_t __iomem *pa_reg = immr_map(im_ioport);
// printk ("\n Spi Read 0: \n");
tbdf = cpm->tbase;
rbdf = cpm->rbase;
out_be16(&pa_reg->iop_pcdat, (in_be16(&pa_reg->iop_pcdat)) & 0xfffb );
// pc13 as low for dsp
if (count > 8192)
count = 8192;
// printk ("\n Spi Read 1: \n");
out_be16(&spi_ram->rbptr, in_be16(&spi_ram->rbase));
out_be16(&spi_ram->tbptr, in_be16(&spi_ram->tbase));
out_be16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP| BD_SC_READY |
BD_SC_INTRPT);
out_be16(&tbdf->cbd_datlen, count);
out_be16(&rbdf->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT | BD_SC_EMPTY);
out_be16(&rbdf->cbd_datlen, count);
// cpm->txbuf[0] = (u_char*)(((uint)cpm->txbuf[0] +15) & ~15);
for(i =0;i<count;i++)
cpm->txbuf[i] =0x10 + i *3;
// memset(cpm->txbuf[0], 0x55, count);
/* Begin transmission */
out_8(&cpm->spi_reg->spcom, 0x80);
// printk ("\n Spi Read 2: \n");
// wait_event(cpm->spi_wait, (!(in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY)));
ret = wait_event_timeout(cpm->spi_wait,
!(in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY),
1 * HZ);
if (ret == 0) {
printk ("\n Spi wait event timeout : \n");
ret = -EREMOTEIO;
goto out_err;
}
udelay (30);
printk ("\n Spi Read 3 : \n");
cpm->rxbuf[0] = (u_char *) (((ulong) cpm->rxbuf[0] + 1) & ~1);
rxptr = (unsigned char *) cpm->rxbuf[0];
for (i=0; i < count; i++) {
printk(" %x",*rxptr);
rxptr++;
}
printk ("\n");
/*
* Skip address byte
*/
ret = copy_to_user(buf, cpm->rxbuf[0],count);
printk ("\n Spi Read 4%d : \n",ret);
// out_be16(&pa_reg->iop_pcdat, (in_be16(&pa_reg->iop_pcdat)) | 0x0004
); // pc13 as high for dsp
out_err:
mpc885_spi_force_close();
return ret;
}
static ssize_t spi_write (struct file *filep, const char __user *buf,
size_t count, loff_t *off)
{
char *tmp ;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
struct spi_ram __iomem *spi_ram = cpm->spi_ram;
iop8xx_t __iomem *pa_reg = immr_map(im_ioport);
tbdf = cpm->tbase;
rbdf = cpm->rbase;
printk ("\nin driver spi write\n");
if (count > 8192)
count = 8192;
out_be16(&spi_ram->rbptr, in_be16(&spi_ram->rbase));
out_be16(&spi_ram->tbptr, in_be16(&spi_ram->tbase));
out_be16(&pa_reg->iop_pcdat, (in_be16(&pa_reg->iop_pcdat)) & 0xfffb );
// pc13 as low for dsp
out_be16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP| BD_SC_READY |
BD_SC_INTRPT);
out_be16(&tbdf->cbd_datlen, count);
out_be16(&rbdf->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT | BD_SC_EMPTY);
out_be16(&rbdf->cbd_datlen, 0);
if(copy_from_user(cpm->txbuf[0], buf, count)) {
return -EFAULT;
}
/* Begin transmission */
out_8(&cpm->spi_reg->spcom, 0x80);
wait_event(cpm->spi_wait,!(in_be16(&tbdf->cbd_sc) & BD_SC_READY));
// out_be16(&pa_reg->iop_pcdat, (in_be16(&pa_reg->iop_pcdat)) | 0x0004
); // pc13 as high for dsp
return 0;
}
static struct file_operations spiops = {
.open = spi_open,
.read = spi_read,
.write = spi_write,
};
static int __devinit mpc885_spi_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
int result;
iop8xx_t __iomem *pa_reg = immr_map(im_ioport);
printk ("\n*********in mpc885 spi probe**************\n");
cpm = kzalloc(sizeof(struct cpm_spi), GFP_KERNEL);
if (!cpm)
return -ENOMEM;
cpm->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, cpm);
result = mpc885_spi_setup(cpm);
if (result) {
printk("Unable to init hardware\n");
goto out_free;
}
out_be16(&pa_reg->iop_pcdir, (in_be16(&pa_reg->iop_pcdir)) | 0x0004 );
//pc13 //dsp chip
out_be16(&pa_reg->iop_pcpar, (in_be16(&pa_reg->iop_pcpar)) & 0xfffb );
/*
* Register with char
*/
result = register_chrdev(MPC885_SPI_MAJOR, "spi_mpc885", &spiops);
if (result)
{
printk("Unable to register spi char dev driver\n");
goto out_shut;
}
return 0;
out_shut:
mpc885_spi_shutdown(cpm);
out_free:
dev_set_drvdata(&ofdev->dev, NULL);
kfree(cpm);
return result;
}
static int __devexit mpc885_spi_remove(struct of_device *ofdev)
{
struct cpm_spi *cpm = dev_get_drvdata(&ofdev->dev);
unregister_chrdev(MPC885_SPI_MAJOR, "spi_mpc885");
mpc885_spi_shutdown(cpm);
dev_set_drvdata(&ofdev->dev, NULL);
kfree(cpm);
return 0;
}
static const struct of_device_id mpc885_spi_match[] = {
{
.compatible = "fsl,mpc885-spi",
},
{},
};
static struct of_platform_driver mpc885_spi_driver = {
.match_table = mpc885_spi_match,
.probe =mpc885_spi_probe,
.remove = __devexit_p(mpc885_spi_remove),
.driver = {
.name = "fsl-spi-mpc885",
.owner = THIS_MODULE,
}
};
static int __init mpc885_spi_init(void)
{
return of_register_platform_driver(&mpc885_spi_driver);
}
static void __exit mpc885_spi_exit(void)
{
of_unregister_platform_driver(&mpc885_spi_driver);
}
module_init(mpc885_spi_init);
module_exit(mpc885_spi_exit);
MODULE_DESCRIPTION("SPI-Bus adapter routines for MPC885 board");
MODULE_LICENSE("GPL");
_______________________________________________
eldk mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/eldk