From patchwork Sun Oct 11 03:54:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mingyu Li X-Patchwork-Id: 528710 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from arrakis.dune.hu (arrakis.dune.hu [78.24.191.176]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3FA6C1402C2 for ; Sun, 11 Oct 2015 15:00:37 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=Nd4/A02s; dkim-atps=neutral Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id D6BCD280409; Sun, 11 Oct 2015 05:55:18 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on arrakis.dune.hu X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,FREEMAIL_FROM, T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 336F8283FA7 for ; Sun, 11 Oct 2015 05:53:35 +0200 (CEST) X-policyd-weight: using cached result; rate:hard: -8.5 Received: from mail-pa0-f48.google.com (mail-pa0-f48.google.com [209.85.220.48]) by arrakis.dune.hu (Postfix) with ESMTPS for ; Sun, 11 Oct 2015 05:53:22 +0200 (CEST) Received: by pabve7 with SMTP id ve7so64712961pab.2 for ; Sat, 10 Oct 2015 20:54:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pXPm/0K2DwY0r7kXAfb9iSng8enVYvoXxaDN9SbfiuE=; b=Nd4/A02snQ6hfnvcyl7E5hIk8knYX4CVIKyft3sZ+ZpPqD1ibFfDbvO65mUoywhSMJ /BrG1vhxihiXajfi8SH3PKmKmJWKpH9hSjPCLt8vbHK6Drky6CB3a+u/sdTuvdil70j5 zJub7424QDuS5jum3ub3LC4nuHs851iWm+jDPBYRW+XLkXkwC9RAG9SUORXb2BUiT1Yh VrPYThP626ZjSvwG6oqCb4wt8uesjVz/8CsEFYKyglRp5skavt121i2cU3AcY9FNMQPC xg5e1pUNH/dihPEkYXb94Qy3zGX9UsLefeF1NjHjeC5eVFzc4LK6hwvYcRyOKufoVMM7 ozLA== X-Received: by 10.66.194.138 with SMTP id hw10mr26365348pac.71.1444535690871; Sat, 10 Oct 2015 20:54:50 -0700 (PDT) Received: from localhost.localdomain (f45hc114.RAS.nctu.edu.tw. [140.113.45.114]) by smtp.gmail.com with ESMTPSA id ux7sm10833184pac.10.2015.10.10.20.54.49 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 10 Oct 2015 20:54:50 -0700 (PDT) From: Michael Lee To: blogic@openwrt.org Date: Sun, 11 Oct 2015 11:54:33 +0800 Message-Id: <1444535674-3117-7-git-send-email-igvtee@gmail.com> X-Mailer: git-send-email 2.3.6 In-Reply-To: <1444535674-3117-1-git-send-email-igvtee@gmail.com> References: <1444535674-3117-1-git-send-email-igvtee@gmail.com> Cc: openwrt-devel@lists.openwrt.org Subject: [OpenWrt-Devel] [PATCH 7/8] ramips: use transfer_one instead of transfer_one_message on mt7621 spi X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openwrt-devel-bounces@lists.openwrt.org Sender: "openwrt-devel" use kernel buildin transfer_one_message. we only need to implement transfer_one the hardware support max 5 bytes for opcode and address. max 32 bytes for tx/rx data. when first transfer fill data to op/addr register then wait second transfer and fill data to data register. finally start hardware transfer Signed-off-by: Michael Lee --- ...0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch | 265 ++++++++------------- 1 file changed, 103 insertions(+), 162 deletions(-) diff --git a/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch b/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch index 1b2476c..57ab71d 100644 --- a/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch +++ b/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch @@ -25,7 +25,7 @@ obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o --- /dev/null +++ b/drivers/spi/spi-mt7621.c -@@ -0,0 +1,623 @@ +@@ -0,0 +1,564 @@ +/* + * spi-mt7621.c -- MediaTek MT7621 SPI controller driver + * @@ -141,7 +141,26 @@ +#define MT7621_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \ + SPI_CS_HIGH) + -+struct mt7621_spi; ++struct mt7621_mb_reg { ++ u32 mosi_bit:12, ++ miso_bit:12, ++ cmd_bit:8; ++}; ++ ++struct mt7621_spi_data { ++ struct spi_message *msg; ++ union { ++ u32 mb_reg; ++ struct mt7621_mb_reg mb; ++ }; ++}; ++ ++struct mt7621_spi_buf { ++ union { ++ u32 data[8]; ++ u8 buf[32]; ++ }; ++}; + +struct mt7621_spi { + struct spi_master *master; @@ -150,6 +169,8 @@ + u16 wait_loops; + u16 mode; + struct clk *clk; ++ ++ struct mt7621_spi_data data; +}; + +static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) @@ -273,190 +294,109 @@ + mt7621_spi_read(rs, MT7621_SPI_SPACE)); +} + -+/* copy from spi.c */ -+static void spi_set_cs(struct spi_device *spi, bool enable) ++static void mt7621_fill_cmd(struct mt7621_spi *rs, ++ const u8 *data, unsigned len) +{ -+ if (spi->mode & SPI_CS_HIGH) -+ enable = !enable; ++ struct mt7621_spi_buf tmp; + -+ if (spi->cs_gpio >= 0) -+ gpio_set_value(spi->cs_gpio, !enable); -+ else if (spi->master->set_cs) -+ spi->master->set_cs(spi, !enable); -+} -+ -+static int mt7621_spi_transfer_half_duplex(struct spi_master *master, -+ struct spi_message *m) -+{ -+ struct mt7621_spi *rs = spi_master_get_devdata(master); -+ struct spi_device *spi = m->spi; -+ struct spi_transfer *t = NULL; -+ int status = 0; -+ int i, len = 0; -+ int rx_len = 0; -+ u32 data[9] = { 0 }; -+ u32 val; ++ rs->data.mb.cmd_bit = len << 3; + -+ mt7621_spi_wait_ready(rs, 1); -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ const u8 *buf = t->tx_buf; -+ -+ if (t->rx_buf) -+ rx_len += t->len; -+ -+ if (!buf) -+ continue; -+ -+ if (WARN_ON(len + t->len > 36)) { -+ status = -EIO; -+ goto msg_done; -+ } -+ -+ for (i = 0; i < t->len; i++, len++) -+ data[len / 4] |= buf[i] << (8 * (len & 3)); -+ } -+ -+ if (WARN_ON(rx_len > 32)) { -+ status = -EIO; -+ goto msg_done; ++ if (len == 5) { ++ tmp.data[0] = mt7621_spi_read(rs, MT7621_SPI_TRANS); ++ tmp.data[0] &= ~(SPITRANS_ADDREXT_MASK << SPITRANS_ADDREXT_OFFSET); ++ tmp.data[0] |= (data[0] << SPITRANS_ADDREXT_OFFSET); ++ mt7621_spi_write(rs, MT7621_SPI_TRANS, tmp.data[0]); ++ data++; ++ len--; + } + -+ data[0] = swab32(data[0]); ++ tmp.data[0] = 0; ++ memcpy(tmp.buf, data, len); ++ tmp.data[0] = cpu_to_be32(tmp.data[0]); + if (len < 4) -+ data[0] >>= (4 - len) * 8; -+ -+ for (i = 0; i < len; i += 4) -+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]); -+ -+ val = (min_t(int, len, 4) * 8) << 24; -+ if (len > 4) -+ val |= (len - 4) * 8; -+ val |= (rx_len * 8) << 12; -+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); -+ -+ spi_set_cs(spi, true); -+ -+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ val |= SPITRANS_START; -+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); -+ -+ mt7621_spi_wait_ready(rs, 36); -+ -+ spi_set_cs(spi, false); -+ -+ for (i = 0; i < rx_len; i += 4) -+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); -+ -+ m->actual_length = len + rx_len; ++ tmp.data[0] >>= ((4 - len) << 3); + -+ len = 0; -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ u8 *buf = t->rx_buf; -+ -+ if (!buf) -+ continue; -+ -+ for (i = 0; i < t->len; i++, len++) -+ buf[i] = data[len / 4] >> (8 * (len & 3)); -+ } -+ -+msg_done: -+ m->status = status; -+ spi_finalize_current_message(master); -+ -+ return 0; ++ mt7621_spi_write(rs, MT7621_SPI_OPCODE, tmp.data[0]); +} + -+static int mt7621_spi_transfer_full_duplex(struct spi_master *master, -+ struct spi_message *m) ++static int mt7621_spi_transfer_one(struct spi_master *master, ++ struct spi_device *spi, struct spi_transfer *xfer) +{ + struct mt7621_spi *rs = spi_master_get_devdata(master); -+ struct spi_device *spi = m->spi; -+ unsigned int speed = spi->max_speed_hz; -+ struct spi_transfer *t = NULL; -+ int status = 0; -+ int i, len = 0; -+ int rx_len = 0; -+ u32 data[9] = { 0 }; -+ u32 val = 0; -+ -+ mt7621_spi_wait_ready(rs, 1); -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ const u8 *buf = t->tx_buf; -+ -+ if (t->rx_buf) -+ rx_len += t->len; -+ -+ if (!buf) -+ continue; -+ -+ if (WARN_ON(len + t->len > 16)) { -+ status = -EIO; -+ goto msg_done; ++ int i, last_xfer, len, ret = 0; ++ struct mt7621_spi_buf tmp; ++ ++ if (rs->data.mb.cmd_bit == 0) { ++ if (unlikely(!xfer->tx_buf || (xfer->len > 5))) { ++ dev_err(&spi->dev, "error op/addr length: %d\n", ++ xfer->len); ++ ret = -EINVAL; ++ goto err; + } -+ -+ for (i = 0; i < t->len; i++, len++) -+ data[len / 4] |= buf[i] << (8 * (len & 3)); -+ if (speed > t->speed_hz) -+ speed = t->speed_hz; -+ } -+ -+ if (WARN_ON(rx_len > 16)) { -+ status = -EIO; -+ goto msg_done; ++ mt7621_fill_cmd(rs, xfer->tx_buf, xfer->len); ++ last_xfer = list_is_last(&xfer->transfer_list, ++ &rs->data.msg->transfers); ++ } else { ++ if (unlikely(xfer->len > 32)) { ++ dev_err(&spi->dev, "error data length: %d\n", ++ xfer->len); ++ ret = -EINVAL; ++ goto err; ++ } ++ if (xfer->tx_buf) { ++ rs->data.mb.mosi_bit = xfer->len << 3; ++ memcpy(tmp.buf, xfer->tx_buf, xfer->len); ++ for (i = 0; i < xfer->len; i += 4) ++ mt7621_spi_write(rs, (MT7621_SPI_DATA0 + i), ++ tmp.data[(i >> 2)]); ++ } ++ if (xfer->rx_buf) ++ rs->data.mb.miso_bit = xfer->len << 3; ++ last_xfer = 1; + } + -+ for (i = 0; i < len; i += 4) -+ mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]); -+ -+ val |= len * 8; -+ val |= (rx_len * 8) << 12; -+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); ++ if (!last_xfer) ++ return ret; + -+ spi_set_cs(spi, true); ++ /* set more buf size */ ++ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, rs->data.mb_reg); + -+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ val |= SPITRANS_START; -+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); ++ /* start transaction */ ++ mt7621_spi_setbits(rs, MT7621_SPI_TRANS, SPITRANS_START); + -+ mt7621_spi_wait_ready(rs, 36); -+ -+ spi_set_cs(spi, false); -+ -+ for (i = 0; i < rx_len; i += 4) -+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i); -+ -+ m->actual_length = rx_len; -+ -+ len = 0; -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ u8 *buf = t->rx_buf; -+ -+ if (!buf) -+ continue; ++ len = (rs->data.mb.cmd_bit + rs->data.mb.miso_bit + ++ rs->data.mb.mosi_bit) >> 3; ++ ret = mt7621_spi_wait_ready(rs, len); ++ if (ret) { ++ dev_err(&spi->dev, "spi wait timeout\n"); ++ goto err; ++ } + -+ for (i = 0; i < t->len; i++, len++) -+ buf[i] = data[len / 4] >> (8 * (len & 3)); ++ if (xfer->rx_buf) { ++ for (i = 0; i < xfer->len; i += 4) ++ tmp.data[(i >> 2)] = mt7621_spi_read(rs, ++ (MT7621_SPI_DATA0 + i)); ++ memcpy(xfer->rx_buf, tmp.buf, xfer->len); + } + -+msg_done: -+ m->status = status; -+ spi_finalize_current_message(master); ++err: ++ rs->data.mb_reg = 0; ++ if (unlikely(ret)) ++ mt7621_dump_reg(master, __func__); + -+ return 0; ++ return ret; +} + -+static int mt7621_spi_transfer_one_message(struct spi_master *master, -+ struct spi_message *m) ++/* copy from spi.c */ ++static void spi_set_cs(struct spi_device *spi, bool enable) +{ -+ struct spi_device *spi = m->spi; -+ int cs = spi->chip_select; ++ if (spi->mode & SPI_CS_HIGH) ++ enable = !enable; + -+ if (cs) -+ return mt7621_spi_transfer_full_duplex(master, m); -+ return mt7621_spi_transfer_half_duplex(master, m); ++ if (spi->cs_gpio >= 0) ++ gpio_set_value(spi->cs_gpio, !enable); ++ else if (spi->master->set_cs) ++ spi->master->set_cs(spi, !enable); +} + +static int mt7621_spi_setup(struct spi_device *spi) @@ -504,6 +444,7 @@ + struct spi_device *spi = msg->spi; + u32 reg; + ++ rs->data.msg = msg; + if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz)) + return 0; + @@ -591,7 +532,7 @@ + master->setup = mt7621_spi_setup; + master->prepare_message = mt7621_spi_prepare_message; + master->set_cs = mt7621_spi_set_cs; -+ master->transfer_one_message = mt7621_spi_transfer_one_message; ++ master->transfer_one = mt7621_spi_transfer_one; + + dev_set_drvdata(&pdev->dev, master); +