diff mbox

ENC28J60 works with half-duplex DMA

Message ID BANLkTi=_W2=MrBu6Xxo5M+eQM0jsJiXrzQ@mail.gmail.com
State Deferred, archived
Delegated to: David Miller
Headers show

Commit Message

Davide Rizzo May 15, 2011, 10:03 a.m. UTC
---
diff mbox

Patch

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>
---
diff -urNp linux-2.6.38/drivers/net/enc28j60.c linux-2.6.38.elpa/drivers/net/enc28j60.c
--- linux-2.6.38/drivers/net/enc28j60.c	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38.elpa/drivers/net/enc28j60.c	2011-05-14 09:56:05.701797208 +0200
@@ -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");