From patchwork Mon May 16 05:33:08 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Davide Rizzo X-Patchwork-Id: 95674 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 7A8BAB6EF1 for ; Mon, 16 May 2011 15:33:16 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751052Ab1EPFdK (ORCPT ); Mon, 16 May 2011 01:33:10 -0400 Received: from mail-iw0-f174.google.com ([209.85.214.174]:53942 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750906Ab1EPFdJ (ORCPT ); Mon, 16 May 2011 01:33:09 -0400 Received: by iwn34 with SMTP id 34so3647270iwn.19 for ; Sun, 15 May 2011 22:33:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:date:message-id:subject:from:to :content-type; bh=Vu1HyovwiYzX5MNTVN3V/2Y9cL7+hyV1Gkq2ZAAHrkU=; b=tv82UKfXeHbD8AIJCu2kcTxhbY//CGS9Xhv7dzJ/iz/QTcIXPztvdlW4qk7Om6HbtE X6T3152DmSUvll7SkRpZxoHXNauMVxZedKM0gGI8+scsx48xNJoicdCrUTZN6Q74pTdL UYxK7aY+TvHtLAqiLn+5TlU2aSTvH/00lPVd8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=wgIdWAWUvyBcx2epbqB5G4bnWW9d+I01FNMMH9rvOd++ndlVwnKfXUQebqtzi4ufHK mOdOxr64Pv+W8TG5Zowx01Tk8P8KGCmNho2sGi1dh/1/RxrAK66HXeyKDFLOZAxoRax+ pgcZrf9IVE1v1yf33DVDsfefrDo7TW02bhbEw= MIME-Version: 1.0 Received: by 10.42.213.137 with SMTP id gw9mr4625568icb.158.1305523988789; Sun, 15 May 2011 22:33:08 -0700 (PDT) Received: by 10.231.30.75 with HTTP; Sun, 15 May 2011 22:33:08 -0700 (PDT) Date: Mon, 16 May 2011 07:33:08 +0200 Message-ID: Subject: [PATCH] 2.6.38 ENC28J60 works with half-duplex DMA From: Davide Rizzo To: netdev@vger.kernel.org Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Please consider this patch, that allows ENC28J60 to be used on machines with half-duplex DMA on SPI 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 --- 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");