blob: 9f60fdb51091451630603a7fe0bd2433d2eee1e9 [file] [log] [blame]
/*
* c2k_spi_common.c
*
* Copyright (C) 2004,2005 Mindspeed Technologies, 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 <common.h>
#include <linux/byteorder/generic.h>
#include <linux/byteorder/little_endian.h>
#include <spi/fast_spi.h>
#include <mach/dma.h>
#include <common.h>
#include <asm/io.h>
#include <mach/comcerto_spi.h>
/**
* do_write_read_transfer -
*
*
*/
int do_write_read_transfer(struct spi_adapter *spi, u8 fs, u8 *wbuf, U32 *wlen, u8 *rbuf, U32 *rlen)
{
u32 sr, dr;
U32 wlen_now = 0, rlen_now = 0;
int rc = 0;
while (wlen_now < *wlen) {
sr = readl(spi->membase + COMCERTO_SPI_SR);
if (sr & TFNF) {
if (wlen_now < *wlen) {
writew(cpu_to_le16((u16) *wbuf), spi->membase + COMCERTO_SPI_DR);
wbuf++;
wlen_now++;
}
}
}
while (rlen_now < *rlen) {
sr = readl(spi->membase + COMCERTO_SPI_SR);
if (sr & (RFF | DCOL)) {
/* read overrun, data collision */
printf ("%s: sr=0x%x: Read Overrun.\n", __func__, sr);
rc = -1;
goto out;
}
if (sr & RFNE) {
dr = readw(spi->membase + COMCERTO_SPI_DR);
if (rlen_now < *rlen) {
*rbuf = (u8) (le16_to_cpu(dr) & 0xff);
rbuf++;
rlen_now++;
} else {
printf ("%s: Read Overflow.\n", __func__);
/* read overflow */
rc = -1;
goto out;
}
}
}
out:
*rlen = rlen_now;
*wlen = wlen_now;
return rc;
}
int do_eeprom_read(struct spi_adapter *spi, u8 fs, u8 *wbuf, U32 *wlen, u8 *rbuf, U32 *ndf)
{
u32 sr, dr;
U32 wlen_now = 0, rlen_now = 0;
int rc = 0;
while (wlen_now < *wlen) {
sr = __raw_readl(spi->membase + COMCERTO_SPI_SR);
if (sr & TFNF) {
if (wlen_now < *wlen) {
__raw_writew(cpu_to_le16((u16) *wbuf), spi->membase + COMCERTO_SPI_DR);
wbuf++;
wlen_now++;
}
}
}
while (rlen_now < *ndf) {
sr = __raw_readl(spi->membase + COMCERTO_SPI_SR);
if (sr & (RFF | DCOL)) {
/* read overrun, data collision */
rc = -1;
goto out;
}
if (sr & RFNE) {
dr = __raw_readw(spi->membase + COMCERTO_SPI_DR);
if (rlen_now < *ndf) {
*rbuf = (u8) (le16_to_cpu(dr) & 0xff);
rbuf++;
rlen_now++;
} else {
/* read overflow */
rc = -1;
goto out;
}
}
}
out:
*ndf = rlen_now;
*wlen = wlen_now;
return rc;
}
/**
* do_write_only_transfer8 -
*
*
*/
int do_write_only_transfer8(struct spi_adapter *spi, u8 *buf, U32 *len)
{
U32 len_now;
int rc = 0;
U32 tmp = *len;
u32 dr = spi->membase + COMCERTO_SPI_DR;
u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
while (tmp)
{
len_now = 8 - readl(txflr);
if (len_now > tmp)
len_now = tmp;
tmp -= len_now;
/* warm-up write fifo to avoid underruns */
while (len_now--)
{
writew(cpu_to_le16((u16) *buf++), dr);
}
}
*len -= tmp;
return rc;
}
/**
* do_write_only_transfer -
*
*
*/
int do_write_only_transfer16(struct spi_adapter *spi, u16 *buf, U32 *len)
{
U32 len_now;
int rc = 0;
U32 tmp = *len;
u32 dr = spi->membase + COMCERTO_SPI_DR;
u32 txflr = spi->membase + COMCERTO_SPI_TXFLR;
while (tmp)
{
len_now = 8 - readl(txflr);
if (len_now > tmp)
len_now = tmp;
tmp -= len_now;
/* warm-up write fifo to avoid underruns */
while (len_now--)
writew(cpu_to_le16(*buf++), dr);
}
*len -= tmp;
return rc;
}
/**
* do_read_only_transfer -
*
*
*/
int do_read_only_transfer8(struct spi_adapter *spi, u8 *buf, U32 *len)
{
U32 len_now;
int rc = 0;
U32 tmp = *len;
u32 dr = spi->membase + COMCERTO_SPI_DR;
u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
/* start the serial clock */
writew(0, dr);
while (tmp)
{
len_now = readl(rxflr);
if (len_now > tmp)
len_now = tmp;
tmp -= len_now;
while (len_now--) {
*buf = (u8) (le16_to_cpu(readw(dr)) & 0xff);
buf++;
}
}
*len -= tmp;
return rc;
}
/**
* do_read_only_transfer -
*
*
*/
int do_read_only_transfer16(struct spi_adapter *spi, u16 *buf, U32 *len)
{
U32 len_now;
int rc = 0;
U32 tmp = *len;
u32 dr = spi->membase + COMCERTO_SPI_DR;
u32 rxflr = spi->membase + COMCERTO_SPI_RXFLR;
/* start the serial clock */
writew(0, dr);
while (tmp)
{
len_now = readl(rxflr);
if (len_now > tmp)
len_now = tmp;
tmp -= len_now;
while (len_now--) {
*buf = le16_to_cpu(readw(dr));
buf++;
}
}
*len -= tmp;
return rc;
}
/***/