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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.11-rc1 362 lines 8.5 kB view raw
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 30struct octeon_spi { 31 struct spi_master *my_master; 32 u64 register_base; 33 u64 last_cfg; 34 u64 cs_enax; 35}; 36 37struct octeon_spi_setup { 38 u32 max_speed_hz; 39 u8 chip_select; 40 u8 mode; 41 u8 bits_per_word; 42}; 43 44static 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 56static 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 169static 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 182static 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 } 217err: 218 msg->status = status; 219 msg->actual_length = total_len; 220 spi_finalize_current_message(master); 221 return status; 222} 223 224static 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 237static 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 257static 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 264static int octeon_spi_nop_transfer_hardware(struct spi_master *master) 265{ 266 return 0; 267} 268 269static int 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; 324fail: 325 spi_master_put(master); 326 return err; 327} 328 329static int 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 342static struct of_device_id octeon_spi_match[] = { 343 { .compatible = "cavium,octeon-3010-spi", }, 344 {}, 345}; 346MODULE_DEVICE_TABLE(of, octeon_spi_match); 347 348static 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 = octeon_spi_remove, 356}; 357 358module_platform_driver(octeon_spi_driver); 359 360MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); 361MODULE_AUTHOR("David Daney"); 362MODULE_LICENSE("GPL");