Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: Add SPI master controller for OCTEON SOCs.

Add the driver, link it into the kbuild system and provide device tree
binding documentation.

Signed-off-by: David Daney <david.daney@cavium.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Patchwork: http://patchwork.linux-mips.org/patch/4292/
Signed-off-by: John Crispin <blogic@openwrt.org>

authored by

David Daney and committed by
John Crispin
6b52c00f 95d585fc

+403
+33
Documentation/devicetree/bindings/spi/spi-octeon.txt
··· 1 + Cavium, Inc. OCTEON SOC SPI master controller. 2 + 3 + Required properties: 4 + - compatible : "cavium,octeon-3010-spi" 5 + - reg : The register base for the controller. 6 + - interrupts : One interrupt, used by the controller. 7 + - #address-cells : <1>, as required by generic SPI binding. 8 + - #size-cells : <0>, also as required by generic SPI binding. 9 + 10 + Child nodes as per the generic SPI binding. 11 + 12 + Example: 13 + 14 + spi@1070000001000 { 15 + compatible = "cavium,octeon-3010-spi"; 16 + reg = <0x10700 0x00001000 0x0 0x100>; 17 + interrupts = <0 58>; 18 + #address-cells = <1>; 19 + #size-cells = <0>; 20 + 21 + eeprom@0 { 22 + compatible = "st,m95256", "atmel,at25"; 23 + reg = <0>; 24 + spi-max-frequency = <5000000>; 25 + spi-cpha; 26 + spi-cpol; 27 + 28 + pagesize = <64>; 29 + size = <32768>; 30 + address-width = <16>; 31 + }; 32 + }; 33 +
+7
drivers/spi/Kconfig
··· 237 237 help 238 238 This is the driver for OpenCores tiny SPI master controller. 239 239 240 + config SPI_OCTEON 241 + tristate "Cavium OCTEON SPI controller" 242 + depends on CPU_CAVIUM_OCTEON 243 + help 244 + SPI host driver for the hardware found on some Cavium OCTEON 245 + SOCs. 246 + 240 247 config SPI_OMAP_UWIRE 241 248 tristate "OMAP1 MicroWire" 242 249 depends on ARCH_OMAP1
+1
drivers/spi/Makefile
··· 38 38 obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o 39 39 obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o 40 40 obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o 41 + obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o 41 42 obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o 42 43 obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o 43 44 obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
+362
drivers/spi/spi-octeon.c
··· 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/init.h> 15 + #include <linux/io.h> 16 + #include <linux/of.h> 17 + 18 + #include <asm/octeon/octeon.h> 19 + #include <asm/octeon/cvmx-mpi-defs.h> 20 + 21 + #define OCTEON_SPI_CFG 0 22 + #define OCTEON_SPI_STS 0x08 23 + #define OCTEON_SPI_TX 0x10 24 + #define OCTEON_SPI_DAT0 0x80 25 + 26 + #define OCTEON_SPI_MAX_BYTES 9 27 + 28 + #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 29 + 30 + struct octeon_spi { 31 + struct spi_master *my_master; 32 + u64 register_base; 33 + u64 last_cfg; 34 + u64 cs_enax; 35 + }; 36 + 37 + struct octeon_spi_setup { 38 + u32 max_speed_hz; 39 + u8 chip_select; 40 + u8 mode; 41 + u8 bits_per_word; 42 + }; 43 + 44 + static void octeon_spi_wait_ready(struct octeon_spi *p) 45 + { 46 + union cvmx_mpi_sts mpi_sts; 47 + unsigned int loops = 0; 48 + 49 + do { 50 + if (loops++) 51 + __delay(500); 52 + mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS); 53 + } while (mpi_sts.s.busy); 54 + } 55 + 56 + static int octeon_spi_do_transfer(struct octeon_spi *p, 57 + struct spi_message *msg, 58 + struct spi_transfer *xfer, 59 + bool last_xfer) 60 + { 61 + union cvmx_mpi_cfg mpi_cfg; 62 + union cvmx_mpi_tx mpi_tx; 63 + unsigned int clkdiv; 64 + unsigned int speed_hz; 65 + int mode; 66 + bool cpha, cpol; 67 + int bits_per_word; 68 + const u8 *tx_buf; 69 + u8 *rx_buf; 70 + int len; 71 + int i; 72 + 73 + struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi); 74 + 75 + speed_hz = msg_setup->max_speed_hz; 76 + mode = msg_setup->mode; 77 + cpha = mode & SPI_CPHA; 78 + cpol = mode & SPI_CPOL; 79 + bits_per_word = msg_setup->bits_per_word; 80 + 81 + if (xfer->speed_hz) 82 + speed_hz = xfer->speed_hz; 83 + if (xfer->bits_per_word) 84 + bits_per_word = xfer->bits_per_word; 85 + 86 + if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) 87 + speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; 88 + 89 + clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); 90 + 91 + mpi_cfg.u64 = 0; 92 + 93 + mpi_cfg.s.clkdiv = clkdiv; 94 + mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0; 95 + mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0; 96 + mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0; 97 + mpi_cfg.s.idlelo = cpha != cpol; 98 + mpi_cfg.s.cslate = cpha ? 1 : 0; 99 + mpi_cfg.s.enable = 1; 100 + 101 + if (msg_setup->chip_select < 4) 102 + p->cs_enax |= 1ull << (12 + msg_setup->chip_select); 103 + mpi_cfg.u64 |= p->cs_enax; 104 + 105 + if (mpi_cfg.u64 != p->last_cfg) { 106 + p->last_cfg = mpi_cfg.u64; 107 + cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64); 108 + } 109 + tx_buf = xfer->tx_buf; 110 + rx_buf = xfer->rx_buf; 111 + len = xfer->len; 112 + while (len > OCTEON_SPI_MAX_BYTES) { 113 + for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { 114 + u8 d; 115 + if (tx_buf) 116 + d = *tx_buf++; 117 + else 118 + d = 0; 119 + cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); 120 + } 121 + mpi_tx.u64 = 0; 122 + mpi_tx.s.csid = msg_setup->chip_select; 123 + mpi_tx.s.leavecs = 1; 124 + mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; 125 + mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; 126 + cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); 127 + 128 + octeon_spi_wait_ready(p); 129 + if (rx_buf) 130 + for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { 131 + u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); 132 + *rx_buf++ = (u8)v; 133 + } 134 + len -= OCTEON_SPI_MAX_BYTES; 135 + } 136 + 137 + for (i = 0; i < len; i++) { 138 + u8 d; 139 + if (tx_buf) 140 + d = *tx_buf++; 141 + else 142 + d = 0; 143 + cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); 144 + } 145 + 146 + mpi_tx.u64 = 0; 147 + mpi_tx.s.csid = msg_setup->chip_select; 148 + if (last_xfer) 149 + mpi_tx.s.leavecs = xfer->cs_change; 150 + else 151 + mpi_tx.s.leavecs = !xfer->cs_change; 152 + mpi_tx.s.txnum = tx_buf ? len : 0; 153 + mpi_tx.s.totnum = len; 154 + cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); 155 + 156 + octeon_spi_wait_ready(p); 157 + if (rx_buf) 158 + for (i = 0; i < len; i++) { 159 + u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); 160 + *rx_buf++ = (u8)v; 161 + } 162 + 163 + if (xfer->delay_usecs) 164 + udelay(xfer->delay_usecs); 165 + 166 + return xfer->len; 167 + } 168 + 169 + static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed) 170 + { 171 + switch (speed) { 172 + case 8: 173 + break; 174 + default: 175 + dev_err(&spi->dev, "Error: %d bits per word not supported\n", 176 + speed); 177 + return -EINVAL; 178 + } 179 + return 0; 180 + } 181 + 182 + static int octeon_spi_transfer_one_message(struct spi_master *master, 183 + struct spi_message *msg) 184 + { 185 + struct octeon_spi *p = spi_master_get_devdata(master); 186 + unsigned int total_len = 0; 187 + int status = 0; 188 + struct spi_transfer *xfer; 189 + 190 + /* 191 + * We better have set the configuration via a call to .setup 192 + * before we get here. 193 + */ 194 + if (spi_get_ctldata(msg->spi) == NULL) { 195 + status = -EINVAL; 196 + goto err; 197 + } 198 + 199 + list_for_each_entry(xfer, &msg->transfers, transfer_list) { 200 + if (xfer->bits_per_word) { 201 + status = octeon_spi_validate_bpw(msg->spi, 202 + xfer->bits_per_word); 203 + if (status) 204 + goto err; 205 + } 206 + } 207 + 208 + list_for_each_entry(xfer, &msg->transfers, transfer_list) { 209 + bool last_xfer = &xfer->transfer_list == msg->transfers.prev; 210 + int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); 211 + if (r < 0) { 212 + status = r; 213 + goto err; 214 + } 215 + total_len += r; 216 + } 217 + err: 218 + msg->status = status; 219 + msg->actual_length = total_len; 220 + spi_finalize_current_message(master); 221 + return status; 222 + } 223 + 224 + static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) 225 + { 226 + struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL); 227 + if (!setup) 228 + return NULL; 229 + 230 + setup->max_speed_hz = spi->max_speed_hz; 231 + setup->chip_select = spi->chip_select; 232 + setup->mode = spi->mode; 233 + setup->bits_per_word = spi->bits_per_word; 234 + return setup; 235 + } 236 + 237 + static int octeon_spi_setup(struct spi_device *spi) 238 + { 239 + int r; 240 + struct octeon_spi_setup *new_setup; 241 + struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); 242 + 243 + r = octeon_spi_validate_bpw(spi, spi->bits_per_word); 244 + if (r) 245 + return r; 246 + 247 + new_setup = octeon_spi_new_setup(spi); 248 + if (!new_setup) 249 + return -ENOMEM; 250 + 251 + spi_set_ctldata(spi, new_setup); 252 + kfree(old_setup); 253 + 254 + return 0; 255 + } 256 + 257 + static void octeon_spi_cleanup(struct spi_device *spi) 258 + { 259 + struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); 260 + spi_set_ctldata(spi, NULL); 261 + kfree(old_setup); 262 + } 263 + 264 + static int octeon_spi_nop_transfer_hardware(struct spi_master *master) 265 + { 266 + return 0; 267 + } 268 + 269 + static int __devinit octeon_spi_probe(struct platform_device *pdev) 270 + { 271 + 272 + struct resource *res_mem; 273 + struct spi_master *master; 274 + struct octeon_spi *p; 275 + int err = -ENOENT; 276 + 277 + master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi)); 278 + if (!master) 279 + return -ENOMEM; 280 + p = spi_master_get_devdata(master); 281 + platform_set_drvdata(pdev, p); 282 + p->my_master = master; 283 + 284 + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 285 + 286 + if (res_mem == NULL) { 287 + dev_err(&pdev->dev, "found no memory resource\n"); 288 + err = -ENXIO; 289 + goto fail; 290 + } 291 + if (!devm_request_mem_region(&pdev->dev, res_mem->start, 292 + resource_size(res_mem), res_mem->name)) { 293 + dev_err(&pdev->dev, "request_mem_region failed\n"); 294 + goto fail; 295 + } 296 + p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, 297 + resource_size(res_mem)); 298 + 299 + /* Dynamic bus numbering */ 300 + master->bus_num = -1; 301 + master->num_chipselect = 4; 302 + master->mode_bits = SPI_CPHA | 303 + SPI_CPOL | 304 + SPI_CS_HIGH | 305 + SPI_LSB_FIRST | 306 + SPI_3WIRE; 307 + 308 + master->setup = octeon_spi_setup; 309 + master->cleanup = octeon_spi_cleanup; 310 + master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware; 311 + master->transfer_one_message = octeon_spi_transfer_one_message; 312 + master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware; 313 + 314 + master->dev.of_node = pdev->dev.of_node; 315 + err = spi_register_master(master); 316 + if (err) { 317 + dev_err(&pdev->dev, "register master failed: %d\n", err); 318 + goto fail; 319 + } 320 + 321 + dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); 322 + 323 + return 0; 324 + fail: 325 + spi_master_put(master); 326 + return err; 327 + } 328 + 329 + static int __devexit octeon_spi_remove(struct platform_device *pdev) 330 + { 331 + struct octeon_spi *p = platform_get_drvdata(pdev); 332 + u64 register_base = p->register_base; 333 + 334 + spi_unregister_master(p->my_master); 335 + 336 + /* Clear the CSENA* and put everything in a known state. */ 337 + cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); 338 + 339 + return 0; 340 + } 341 + 342 + static struct of_device_id octeon_spi_match[] = { 343 + { .compatible = "cavium,octeon-3010-spi", }, 344 + {}, 345 + }; 346 + MODULE_DEVICE_TABLE(of, octeon_spi_match); 347 + 348 + static struct platform_driver octeon_spi_driver = { 349 + .driver = { 350 + .name = "spi-octeon", 351 + .owner = THIS_MODULE, 352 + .of_match_table = octeon_spi_match, 353 + }, 354 + .probe = octeon_spi_probe, 355 + .remove = __devexit_p(octeon_spi_remove), 356 + }; 357 + 358 + module_platform_driver(octeon_spi_driver); 359 + 360 + MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); 361 + MODULE_AUTHOR("David Daney"); 362 + MODULE_LICENSE("GPL");