spi-cavium.c (3564B)
1/* 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 4 * 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->chip_select < 4) 61 p->cs_enax |= 1ull << (12 + spi->chip_select); 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 else 77 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->chip_select; 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 else 101 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->chip_select; 107 if (last_xfer) 108 mpi_tx.s.leavecs = xfer->cs_change; 109 else 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)); 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_master *master, 128 struct spi_message *msg) 129{ 130 struct octeon_spi *p = spi_master_get_devdata(master); 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(master); 149 return status; 150}