2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2011, 2012 Cavium, Inc.
9 #include <linux/spi/spi.h>
10 #include <linux/module.h>
11 #include <linux/delay.h>
14 #include "spi-cavium.h"
16 static void octeon_spi_wait_ready(struct octeon_spi *p)
18 union cvmx_mpi_sts mpi_sts;
19 unsigned int loops = 0;
24 mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p));
25 } while (mpi_sts.s.busy);
28 static int octeon_spi_do_transfer(struct octeon_spi *p,
29 struct spi_message *msg,
30 struct spi_transfer *xfer,
33 struct spi_device *spi = msg->spi;
34 union cvmx_mpi_cfg mpi_cfg;
35 union cvmx_mpi_tx mpi_tx;
45 cpha = mode & SPI_CPHA;
46 cpol = mode & SPI_CPOL;
48 clkdiv = p->sys_freq / (2 * xfer->speed_hz);
52 mpi_cfg.s.clkdiv = clkdiv;
53 mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0;
54 mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0;
55 mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0;
56 mpi_cfg.s.idlelo = cpha != cpol;
57 mpi_cfg.s.cslate = cpha ? 1 : 0;
60 if (spi->chip_select < 4)
61 p->cs_enax |= 1ull << (12 + spi->chip_select);
62 mpi_cfg.u64 |= p->cs_enax;
64 if (mpi_cfg.u64 != p->last_cfg) {
65 p->last_cfg = mpi_cfg.u64;
66 writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG(p));
68 tx_buf = xfer->tx_buf;
69 rx_buf = xfer->rx_buf;
71 while (len > OCTEON_SPI_MAX_BYTES) {
72 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
78 writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
81 mpi_tx.s.csid = spi->chip_select;
83 mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
84 mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
85 writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
87 octeon_spi_wait_ready(p);
89 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
90 u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
93 len -= OCTEON_SPI_MAX_BYTES;
96 for (i = 0; i < len; i++) {
102 writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
106 mpi_tx.s.csid = spi->chip_select;
108 mpi_tx.s.leavecs = xfer->cs_change;
110 mpi_tx.s.leavecs = !xfer->cs_change;
111 mpi_tx.s.txnum = tx_buf ? len : 0;
112 mpi_tx.s.totnum = len;
113 writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
115 octeon_spi_wait_ready(p);
117 for (i = 0; i < len; i++) {
118 u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
122 if (xfer->delay_usecs)
123 udelay(xfer->delay_usecs);
128 int octeon_spi_transfer_one_message(struct spi_master *master,
129 struct spi_message *msg)
131 struct octeon_spi *p = spi_master_get_devdata(master);
132 unsigned int total_len = 0;
134 struct spi_transfer *xfer;
136 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
137 bool last_xfer = list_is_last(&xfer->transfer_list,
139 int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
147 msg->status = status;
148 msg->actual_length = total_len;
149 spi_finalize_current_message(master);