Hi,
I attached a driver for the SPI controller of MPC875 that I'm developing. It's
not yet complete, actually, in the mpc8xx_transfer () method simply tries to
transmit 3 bytes (the SPI controller is looped) and thus I expect to receive
the same three bytes. It works sometimes, but not always and I don't know why.
In the init I configure the SPI controller, to do this, I do a ioremap_nocache
of physaddr IMMAP address and then write the relevant registers. I also tried
to put __iomem qualifier to the SPI registers pointers thinking that the writes
to the SPI registers were cached. No success! What could be the problem?
Bye,
Melinda.
-
Everyone is raving about the all-new Yahoo! Mail beta./*
* MPC83xx SPI controller driver.
*
* Maintainer: Kumar Gala
*
* Copyright (C) 2006 Polycom, 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.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* MPC8xx SPI Controller mode register definitions are in commproc.h */
#define SPMODE_LEN(x) ((x-1) << 4)
#define SPMODE_PM(x) ((x))
#define SPI_MAX_BUFFER_SIZE 32
/*
* Default for SPI Mode:
* SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
*/
#define SPMODE_INIT_VAL (SPMODE_CI | SPMODE_DIV16 | SPMODE_REV | \
SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
/* SPIE/SPIM register values */
#define SPIE_MME 0x20 /* Multimaster error */
#define SPIE_TXE 0x10 /* Tx error */
#define SPIE_BSY 0x04/* No rx buffer available */
#define SPIE_TXB 0x02/* Tx buffer transmitted */
#define SPIE_NF 0x01/* Rx buffer filled */
/* SPCOM values */
#define SPCOM_START 0x80/* Start transmission command */
#ifndef BD_SC_ME
#define BD_SC_ME((ushort)0x0001)/* Multi Master Error */
#endif
/*/
int j = 0;
static u8* rxbuffer;
static u8* txbuffer;
void spi_activate_cs(u8 cs, u8 polarity);
void spi_deactivate_cs(u8 cs, u8 polarity);
static car8xx_t *carp;
static spi_t *spi;
static immap_t *immap;
static cpic8xx_t*cpi;
static cpm8xx_t *cp;
static iop8xx_t *iop;
static cbd_t*tbdf;
static cbd_t*rbdf;
static unsigned short r_tbase, r_rbase;
/* SPI Controller driver's private data. */
struct mpc8xx_spi {
struct completion done;
dma_addr_t scratchbuf;
/* lock to avoid contemporaneous transmission */
spinlock_t lock;
unsigned int count;
u32 irq;
unsigned nsecs; /* (clock cycle time)/2 */
u32 inpclk;
u16 mode; /* spi mode in hardware specific way */
void (*activate_cs) (u8 cs, u8 polarity);
void (*deactivate_cs) (u8 cs, u8 polarity);
};
static
u16 mpc8xx_spi_hwmode(u8 mode, int len, u32 inpclk, u32 speedhz)
{
/* DFBRG is zero */
u16 modehw = SPMODE_MSTR ;
/* setup spi mode */
if (mode & SPI_CPOL)
modehw |= SPMODE_CI;
if (mode & SPI_CPHA)
modehw |= SPMODE_CP;
if (!(mode & SPI_LSB_FIRST))
modehw |= SPMODE_REV;
modehw |= SPMODE_LEN(len);
/* Setting desired speed */
modehw |= SPMODE_PM((u8)((inpclk/speedhz)/4-1));
return modehw;
}
static
int mpc8xx_transmit(u8* tx_buf, u8* rx_buf, int tx_size, int rx_size)
{
int result, i;
// copy data to be sent into the transmit buffer
if (tx_buf)
memcpy((void*)(txbuffer), (void*)tx_buf, tx_size);
// BD data length register
tbdf->cbd_datlen = rbdf->cbd_datlen = tx_size + rx_size;
printk("SPI TX: ");
for (i = 0; i < tx_size; i++)
printk("%02X ", txbuffer[i]);
printk("\n");
// BD status/control register
tbdf->cbd_sc = BD_SC_READY | BD_SC_WRAP | BD_SC_LAST;
rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
cp->cp_spmode = 0x4678; // spi mode setting
cp->cp_spmode |= 0x0100;// enable SPI
cp->cp_spie = 0xff; // clear all spi events
cp->cp_spim = 0x37; // mask all SPI events
udelay(10); // Wait 5 microsecs
cp->cp_spcom = 0x80; // start the transfer
udelay(10);
cp->cp_spmode = 0x00; // reset spi mode
udelay(10); // Wait 10 microsecs
// test receive and transmit buffer descriptor for errors
if (rbdf->cbd_sc & (BD_SC_EMPTY | BD_SC_OV | BD_SC_ME))
{
result = -EIO;
}
if (tbdf->cbd_sc & (BD_SC_READY | BD_SC_UN | BD_SC_ME))
{
result = -EIO;
}
// copy the received data into the receive buffer
if (rx_buf)
memcpy((void*)r