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/platform_device.h> 10#include <linux/interrupt.h> 11#include <linux/spi/spi.h> 12#include <linux/module.h> 13#include <linux/delay.h> 14#include <linux/io.h> 15#include <linux/of.h> 16 17#include <asm/octeon/octeon.h> 18#include <asm/octeon/cvmx-mpi-defs.h> 19 20#define OCTEON_SPI_CFG 0 21#define OCTEON_SPI_STS 0x08 22#define OCTEON_SPI_TX 0x10 23#define OCTEON_SPI_DAT0 0x80 24 25#define OCTEON_SPI_MAX_BYTES 9 26 27#define OCTEON_SPI_MAX_CLOCK_HZ 16000000 28 29struct octeon_spi { 30 u64 register_base; 31 u64 last_cfg; 32 u64 cs_enax; 33}; 34 35static void octeon_spi_wait_ready(struct octeon_spi *p) 36{ 37 union cvmx_mpi_sts mpi_sts; 38 unsigned int loops = 0; 39 40 do { 41 if (loops++) 42 __delay(500); 43 mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS); 44 } while (mpi_sts.s.busy); 45} 46 47static int octeon_spi_do_transfer(struct octeon_spi *p, 48 struct spi_message *msg, 49 struct spi_transfer *xfer, 50 bool last_xfer) 51{ 52 struct spi_device *spi = msg->spi; 53 union cvmx_mpi_cfg mpi_cfg; 54 union cvmx_mpi_tx mpi_tx; 55 unsigned int clkdiv; 56 unsigned int speed_hz; 57 int mode; 58 bool cpha, cpol; 59 const u8 *tx_buf; 60 u8 *rx_buf; 61 int len; 62 int i; 63 64 mode = spi->mode; 65 cpha = mode & SPI_CPHA; 66 cpol = mode & SPI_CPOL; 67 68 speed_hz = xfer->speed_hz ? : spi->max_speed_hz; 69 70 clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); 71 72 mpi_cfg.u64 = 0; 73 74 mpi_cfg.s.clkdiv = clkdiv; 75 mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0; 76 mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0; 77 mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0; 78 mpi_cfg.s.idlelo = cpha != cpol; 79 mpi_cfg.s.cslate = cpha ? 1 : 0; 80 mpi_cfg.s.enable = 1; 81 82 if (spi->chip_select < 4) 83 p->cs_enax |= 1ull << (12 + spi->chip_select); 84 mpi_cfg.u64 |= p->cs_enax; 85 86 if (mpi_cfg.u64 != p->last_cfg) { 87 p->last_cfg = mpi_cfg.u64; 88 cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64); 89 } 90 tx_buf = xfer->tx_buf; 91 rx_buf = xfer->rx_buf; 92 len = xfer->len; 93 while (len > OCTEON_SPI_MAX_BYTES) { 94 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { 95 u8 d; 96 if (tx_buf) 97 d = *tx_buf++; 98 else 99 d = 0; 100 cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); 101 } 102 mpi_tx.u64 = 0; 103 mpi_tx.s.csid = spi->chip_select; 104 mpi_tx.s.leavecs = 1; 105 mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; 106 mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; 107 cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); 108 109 octeon_spi_wait_ready(p); 110 if (rx_buf) 111 for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { 112 u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); 113 *rx_buf++ = (u8)v; 114 } 115 len -= OCTEON_SPI_MAX_BYTES; 116 } 117 118 for (i = 0; i < len; i++) { 119 u8 d; 120 if (tx_buf) 121 d = *tx_buf++; 122 else 123 d = 0; 124 cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); 125 } 126 127 mpi_tx.u64 = 0; 128 mpi_tx.s.csid = spi->chip_select; 129 if (last_xfer) 130 mpi_tx.s.leavecs = xfer->cs_change; 131 else 132 mpi_tx.s.leavecs = !xfer->cs_change; 133 mpi_tx.s.txnum = tx_buf ? len : 0; 134 mpi_tx.s.totnum = len; 135 cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); 136 137 octeon_spi_wait_ready(p); 138 if (rx_buf) 139 for (i = 0; i < len; i++) { 140 u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); 141 *rx_buf++ = (u8)v; 142 } 143 144 if (xfer->delay_usecs) 145 udelay(xfer->delay_usecs); 146 147 return xfer->len; 148} 149 150static int octeon_spi_transfer_one_message(struct spi_master *master, 151 struct spi_message *msg) 152{ 153 struct octeon_spi *p = spi_master_get_devdata(master); 154 unsigned int total_len = 0; 155 int status = 0; 156 struct spi_transfer *xfer; 157 158 list_for_each_entry(xfer, &msg->transfers, transfer_list) { 159 bool last_xfer = list_is_last(&xfer->transfer_list, 160 &msg->transfers); 161 int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); 162 if (r < 0) { 163 status = r; 164 goto err; 165 } 166 total_len += r; 167 } 168err: 169 msg->status = status; 170 msg->actual_length = total_len; 171 spi_finalize_current_message(master); 172 return status; 173} 174 175static int octeon_spi_probe(struct platform_device *pdev) 176{ 177 struct resource *res_mem; 178 struct spi_master *master; 179 struct octeon_spi *p; 180 int err = -ENOENT; 181 182 master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi)); 183 if (!master) 184 return -ENOMEM; 185 p = spi_master_get_devdata(master); 186 platform_set_drvdata(pdev, master); 187 188 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 190 if (res_mem == NULL) { 191 dev_err(&pdev->dev, "found no memory resource\n"); 192 err = -ENXIO; 193 goto fail; 194 } 195 if (!devm_request_mem_region(&pdev->dev, res_mem->start, 196 resource_size(res_mem), res_mem->name)) { 197 dev_err(&pdev->dev, "request_mem_region failed\n"); 198 goto fail; 199 } 200 p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, 201 resource_size(res_mem)); 202 203 master->num_chipselect = 4; 204 master->mode_bits = SPI_CPHA | 205 SPI_CPOL | 206 SPI_CS_HIGH | 207 SPI_LSB_FIRST | 208 SPI_3WIRE; 209 210 master->transfer_one_message = octeon_spi_transfer_one_message; 211 master->bits_per_word_mask = SPI_BPW_MASK(8); 212 master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; 213 214 master->dev.of_node = pdev->dev.of_node; 215 err = devm_spi_register_master(&pdev->dev, master); 216 if (err) { 217 dev_err(&pdev->dev, "register master failed: %d\n", err); 218 goto fail; 219 } 220 221 dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); 222 223 return 0; 224fail: 225 spi_master_put(master); 226 return err; 227} 228 229static int octeon_spi_remove(struct platform_device *pdev) 230{ 231 struct spi_master *master = platform_get_drvdata(pdev); 232 struct octeon_spi *p = spi_master_get_devdata(master); 233 u64 register_base = p->register_base; 234 235 /* Clear the CSENA* and put everything in a known state. */ 236 cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); 237 238 return 0; 239} 240 241static const struct of_device_id octeon_spi_match[] = { 242 { .compatible = "cavium,octeon-3010-spi", }, 243 {}, 244}; 245MODULE_DEVICE_TABLE(of, octeon_spi_match); 246 247static struct platform_driver octeon_spi_driver = { 248 .driver = { 249 .name = "spi-octeon", 250 .of_match_table = octeon_spi_match, 251 }, 252 .probe = octeon_spi_probe, 253 .remove = octeon_spi_remove, 254}; 255 256module_platform_driver(octeon_spi_driver); 257 258MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); 259MODULE_AUTHOR("David Daney"); 260MODULE_LICENSE("GPL"); 261