This patch modifies SPI access to take advantage of DMA on machines supporting
only half-duplex SPI DMA (like Samsung S3C2410)
Signed-off-by: Davide Rizzo <elpa.rizzo@gmail.com>
---
@@ -36,6 +36,8 @@
#define SPI_OPLEN 1
+#define FCLK_MAX 20000000
+
#define ENC28J60_MSG_DEFAULT \
(NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
@@ -84,29 +86,33 @@ static struct {
* SPI read buffer
* wait for the SPI transfer and copy received data to destination
*/
-static int
-spi_read_buf(struct enc28j60_net *priv, int len, u8 *data)
+static int spi_read_buf(struct enc28j60_net *priv, int len, u8 *data)
{
- u8 *rx_buf = priv->spi_transfer_buf + 4;
- u8 *tx_buf = priv->spi_transfer_buf;
struct spi_transfer t = {
- .tx_buf = tx_buf,
- .rx_buf = rx_buf,
- .len = SPI_OPLEN + len,
+ .tx_buf = priv->spi_transfer_buf,
+ .rx_buf = NULL,
+ .len = SPI_OPLEN,
+ .cs_change = 0,
+ .speed_hz = FCLK_MAX,
+ };
+ struct spi_transfer r = {
+ .tx_buf = NULL,
+ .rx_buf = data,
+ .len = len,
+ .cs_change = 1,
+ .speed_hz = FCLK_MAX,
};
struct spi_message msg;
int ret;
- tx_buf[0] = ENC28J60_READ_BUF_MEM;
- tx_buf[1] = tx_buf[2] = tx_buf[3] = 0; /* don't care */
+ priv->spi_transfer_buf[0] = ENC28J60_READ_BUF_MEM;
spi_message_init(&msg);
spi_message_add_tail(&t, &msg);
+ spi_message_add_tail(&r, &msg);
ret = spi_sync(priv->spi, &msg);
- if (ret == 0) {
- memcpy(data, &rx_buf[SPI_OPLEN], len);
+ if (ret == 0)
ret = msg.status;
- }
if (ret && netif_msg_drv(priv))
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
__func__, ret);
@@ -114,20 +120,26 @@ spi_read_buf(struct enc28j60_net *priv,
return ret;
}
-/*
- * SPI write buffer
- */
-static int spi_write_buf(struct enc28j60_net *priv, int len,
- const u8 *data)
+static int spi_send(struct enc28j60_net *priv, u8 cmd, int len, const u8 *data)
{
int ret;
+ struct spi_message msg;
+ struct spi_transfer t = {
+ .tx_buf = priv->spi_transfer_buf,
+ .rx_buf = NULL,
+ .len = len + 1,
+ .cs_change = 1,
+ .speed_hz = FCLK_MAX,
+ };
if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0)
ret = -EINVAL;
else {
- priv->spi_transfer_buf[0] = ENC28J60_WRITE_BUF_MEM;
+ spi_message_init(&msg);
+ spi_message_add_tail(&t, &msg);
+ priv->spi_transfer_buf[0] = cmd;
memcpy(&priv->spi_transfer_buf[1], data, len);
- ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1);
+ ret = spi_sync(priv->spi, &msg);
if (ret && netif_msg_drv(priv))
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
__func__, ret);
@@ -136,28 +148,56 @@ static int spi_write_buf(struct enc28j60
}
/*
+ * SPI write buffer
+ */
+static int spi_write_buf(struct enc28j60_net *priv, int len,
+ const u8 *data)
+{
+ return spi_send(priv, ENC28J60_WRITE_BUF_MEM, len, data);
+}
+
+/*
* basic SPI read operation
*/
-static u8 spi_read_op(struct enc28j60_net *priv, u8 op,
- u8 addr)
+static u8 spi_read_op(struct enc28j60_net *priv, u8 op, u8 addr)
{
- u8 tx_buf[2];
- u8 rx_buf[4];
+ u8 tx_buf;
+ u8 rx_buf[SPI_OPLEN + 1];
u8 val = 0;
+ struct spi_transfer t = {
+ .tx_buf = &tx_buf,
+ .rx_buf = NULL,
+ .len = SPI_OPLEN,
+ .cs_change = 0,
+ .speed_hz = FCLK_MAX,
+ };
+ struct spi_transfer r = {
+ .tx_buf = NULL,
+ .rx_buf = rx_buf,
+ .len = SPI_OPLEN,
+ .cs_change = 1,
+ .speed_hz = FCLK_MAX,
+ };
+ struct spi_message msg;
int ret;
- int slen = SPI_OPLEN;
/* do dummy read if needed */
if (addr & SPRD_MASK)
- slen++;
+ r.len++;
+
+ tx_buf = op | (addr & ADDR_MASK);
- tx_buf[0] = op | (addr & ADDR_MASK);
- ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen);
- if (ret)
+ spi_message_init(&msg);
+ spi_message_add_tail(&t, &msg);
+ spi_message_add_tail(&r, &msg);
+ ret = spi_sync(priv->spi, &msg);
+ if (ret == 0)
+ ret = msg.status;
+ if (ret && netif_msg_drv(priv))
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
__func__, ret);
else
- val = rx_buf[slen - 1];
+ val = rx_buf[r.len - 1];
return val;
}
@@ -165,18 +205,9 @@ static u8 spi_read_op(struct enc28j60_ne
/*
* basic SPI write operation
*/
-static int spi_write_op(struct enc28j60_net *priv, u8 op,
- u8 addr, u8 val)
+static int spi_write_op(struct enc28j60_net *priv, u8 op, u8 addr, u8 val)
{
- int ret;
-
- priv->spi_transfer_buf[0] = op | (addr & ADDR_MASK);
- priv->spi_transfer_buf[1] = val;
- ret = spi_write(priv->spi, priv->spi_transfer_buf, 2);
- if (ret && netif_msg_drv(priv))
- printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
- __func__, ret);
- return ret;
+ return spi_send(priv, op | (addr & ADDR_MASK), 1, &val);
}
static void enc28j60_soft_reset(struct enc28j60_net *priv)
@@ -1572,6 +1603,12 @@ static int __devinit enc28j60_probe(stru
dev_set_drvdata(&spi->dev, priv); /* spi to priv reference */
SET_NETDEV_DEV(dev, &spi->dev);
+ /* Configure the SPI bus */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ spi->max_speed_hz = FCLK_MAX;
+ spi_setup(spi);
+
if (!enc28j60_chipset_init(dev)) {
if (netif_msg_probe(priv))
dev_info(&spi->dev, DRV_NAME " chip not found\n");