151 lines · c
1/*2 * This file is subject to the terms and conditions of the GNU General Public3 * License. See the file "COPYING" in the main directory of this archive4 * for more details.5 *6 * Copyright (C) 2011, 2012 Cavium, Inc.7 */8 9#include <linux/spi/spi.h>10#include <linux/module.h>11#include <linux/delay.h>12#include <linux/io.h>13 14#include "spi-cavium.h"15 16static void octeon_spi_wait_ready(struct octeon_spi *p)17{18 union cvmx_mpi_sts mpi_sts;19 unsigned int loops = 0;20 21 do {22 if (loops++)23 __delay(500);24 mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p));25 } while (mpi_sts.s.busy);26}27 28static int octeon_spi_do_transfer(struct octeon_spi *p,29 struct spi_message *msg,30 struct spi_transfer *xfer,31 bool last_xfer)32{33 struct spi_device *spi = msg->spi;34 union cvmx_mpi_cfg mpi_cfg;35 union cvmx_mpi_tx mpi_tx;36 unsigned int clkdiv;37 int mode;38 bool cpha, cpol;39 const u8 *tx_buf;40 u8 *rx_buf;41 int len;42 int i;43 44 mode = spi->mode;45 cpha = mode & SPI_CPHA;46 cpol = mode & SPI_CPOL;47 48 clkdiv = p->sys_freq / (2 * xfer->speed_hz);49 50 mpi_cfg.u64 = 0;51 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;58 mpi_cfg.s.enable = 1;59 60 if (spi_get_chipselect(spi, 0) < 4)61 p->cs_enax |= 1ull << (12 + spi_get_chipselect(spi, 0));62 mpi_cfg.u64 |= p->cs_enax;63 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));67 }68 tx_buf = xfer->tx_buf;69 rx_buf = xfer->rx_buf;70 len = xfer->len;71 while (len > OCTEON_SPI_MAX_BYTES) {72 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {73 u8 d;74 if (tx_buf)75 d = *tx_buf++;76 else77 d = 0;78 writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));79 }80 mpi_tx.u64 = 0;81 mpi_tx.s.csid = spi_get_chipselect(spi, 0);82 mpi_tx.s.leavecs = 1;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));86 87 octeon_spi_wait_ready(p);88 if (rx_buf)89 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {90 u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));91 *rx_buf++ = (u8)v;92 }93 len -= OCTEON_SPI_MAX_BYTES;94 }95 96 for (i = 0; i < len; i++) {97 u8 d;98 if (tx_buf)99 d = *tx_buf++;100 else101 d = 0;102 writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));103 }104 105 mpi_tx.u64 = 0;106 mpi_tx.s.csid = spi_get_chipselect(spi, 0);107 if (last_xfer)108 mpi_tx.s.leavecs = xfer->cs_change;109 else110 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));114 115 octeon_spi_wait_ready(p);116 if (rx_buf)117 for (i = 0; i < len; i++) {118 u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));119 *rx_buf++ = (u8)v;120 }121 122 spi_transfer_delay_exec(xfer);123 124 return xfer->len;125}126 127int octeon_spi_transfer_one_message(struct spi_controller *ctlr,128 struct spi_message *msg)129{130 struct octeon_spi *p = spi_controller_get_devdata(ctlr);131 unsigned int total_len = 0;132 int status = 0;133 struct spi_transfer *xfer;134 135 list_for_each_entry(xfer, &msg->transfers, transfer_list) {136 bool last_xfer = list_is_last(&xfer->transfer_list,137 &msg->transfers);138 int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);139 if (r < 0) {140 status = r;141 goto err;142 }143 total_len += r;144 }145err:146 msg->status = status;147 msg->actual_length = total_len;148 spi_finalize_current_message(ctlr);149 return status;150}151