diff options
| -rw-r--r-- | drivers/spi/spi-rspi.c | 320 | ||||
| -rw-r--r-- | include/linux/spi/rspi.h | 31 |
2 files changed, 345 insertions, 6 deletions
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 354f170eab95..4894bde4bbff 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c | |||
| @@ -31,7 +31,11 @@ | |||
| 31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| 32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
| 33 | #include <linux/clk.h> | 33 | #include <linux/clk.h> |
| 34 | #include <linux/dmaengine.h> | ||
| 35 | #include <linux/dma-mapping.h> | ||
| 36 | #include <linux/sh_dma.h> | ||
| 34 | #include <linux/spi/spi.h> | 37 | #include <linux/spi/spi.h> |
| 38 | #include <linux/spi/rspi.h> | ||
| 35 | 39 | ||
| 36 | #define RSPI_SPCR 0x00 | 40 | #define RSPI_SPCR 0x00 |
| 37 | #define RSPI_SSLP 0x01 | 41 | #define RSPI_SSLP 0x01 |
| @@ -141,6 +145,16 @@ struct rspi_data { | |||
| 141 | spinlock_t lock; | 145 | spinlock_t lock; |
| 142 | struct clk *clk; | 146 | struct clk *clk; |
| 143 | unsigned char spsr; | 147 | unsigned char spsr; |
| 148 | |||
| 149 | /* for dmaengine */ | ||
| 150 | struct sh_dmae_slave dma_tx; | ||
| 151 | struct sh_dmae_slave dma_rx; | ||
| 152 | struct dma_chan *chan_tx; | ||
| 153 | struct dma_chan *chan_rx; | ||
| 154 | int irq; | ||
| 155 | |||
| 156 | unsigned dma_width_16bit:1; | ||
| 157 | unsigned dma_callbacked:1; | ||
| 144 | }; | 158 | }; |
| 145 | 159 | ||
| 146 | static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset) | 160 | static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset) |
| @@ -265,11 +279,125 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, | |||
| 265 | return 0; | 279 | return 0; |
| 266 | } | 280 | } |
| 267 | 281 | ||
| 268 | static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, | 282 | static void rspi_dma_complete(void *arg) |
| 269 | struct spi_transfer *t) | 283 | { |
| 284 | struct rspi_data *rspi = arg; | ||
| 285 | |||
| 286 | rspi->dma_callbacked = 1; | ||
| 287 | wake_up_interruptible(&rspi->wait); | ||
| 288 | } | ||
| 289 | |||
| 290 | static int rspi_dma_map_sg(struct scatterlist *sg, void *buf, unsigned len, | ||
| 291 | struct dma_chan *chan, | ||
| 292 | enum dma_transfer_direction dir) | ||
| 293 | { | ||
| 294 | sg_init_table(sg, 1); | ||
| 295 | sg_set_buf(sg, buf, len); | ||
| 296 | sg_dma_len(sg) = len; | ||
| 297 | return dma_map_sg(chan->device->dev, sg, 1, dir); | ||
| 298 | } | ||
| 299 | |||
| 300 | static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan, | ||
| 301 | enum dma_transfer_direction dir) | ||
| 302 | { | ||
| 303 | dma_unmap_sg(chan->device->dev, sg, 1, dir); | ||
| 304 | } | ||
| 305 | |||
| 306 | static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len) | ||
| 307 | { | ||
| 308 | u16 *dst = buf; | ||
| 309 | const u8 *src = data; | ||
| 310 | |||
| 311 | while (len) { | ||
| 312 | *dst++ = (u16)(*src++); | ||
| 313 | len--; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len) | ||
| 318 | { | ||
| 319 | u8 *dst = buf; | ||
| 320 | const u16 *src = data; | ||
| 321 | |||
| 322 | while (len) { | ||
| 323 | *dst++ = (u8)*src++; | ||
| 324 | len--; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) | ||
| 329 | { | ||
| 330 | struct scatterlist sg; | ||
| 331 | void *buf = NULL; | ||
| 332 | struct dma_async_tx_descriptor *desc; | ||
| 333 | unsigned len; | ||
| 334 | int ret = 0; | ||
| 335 | |||
| 336 | if (rspi->dma_width_16bit) { | ||
| 337 | /* | ||
| 338 | * If DMAC bus width is 16-bit, the driver allocates a dummy | ||
| 339 | * buffer. And, the driver converts original data into the | ||
| 340 | * DMAC data as the following format: | ||
| 341 | * original data: 1st byte, 2nd byte ... | ||
| 342 | * DMAC data: 1st byte, dummy, 2nd byte, dummy ... | ||
| 343 | */ | ||
| 344 | len = t->len * 2; | ||
| 345 | buf = kmalloc(len, GFP_KERNEL); | ||
| 346 | if (!buf) | ||
| 347 | return -ENOMEM; | ||
| 348 | rspi_memory_to_8bit(buf, t->tx_buf, t->len); | ||
| 349 | } else { | ||
| 350 | len = t->len; | ||
| 351 | buf = (void *)t->tx_buf; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) { | ||
| 355 | ret = -EFAULT; | ||
| 356 | goto end_nomap; | ||
| 357 | } | ||
| 358 | desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE, | ||
| 359 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
| 360 | if (!desc) { | ||
| 361 | ret = -EIO; | ||
| 362 | goto end; | ||
| 363 | } | ||
| 364 | |||
| 365 | /* | ||
| 366 | * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be | ||
| 367 | * called. So, this driver disables the IRQ while DMA transfer. | ||
| 368 | */ | ||
| 369 | disable_irq(rspi->irq); | ||
| 370 | |||
| 371 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); | ||
| 372 | rspi_enable_irq(rspi, SPCR_SPTIE); | ||
| 373 | rspi->dma_callbacked = 0; | ||
| 374 | |||
| 375 | desc->callback = rspi_dma_complete; | ||
| 376 | desc->callback_param = rspi; | ||
| 377 | dmaengine_submit(desc); | ||
| 378 | dma_async_issue_pending(rspi->chan_tx); | ||
| 379 | |||
| 380 | ret = wait_event_interruptible_timeout(rspi->wait, | ||
| 381 | rspi->dma_callbacked, HZ); | ||
| 382 | if (ret > 0 && rspi->dma_callbacked) | ||
| 383 | ret = 0; | ||
| 384 | else if (!ret) | ||
| 385 | ret = -ETIMEDOUT; | ||
| 386 | rspi_disable_irq(rspi, SPCR_SPTIE); | ||
| 387 | |||
| 388 | enable_irq(rspi->irq); | ||
| 389 | |||
| 390 | end: | ||
| 391 | rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); | ||
| 392 | end_nomap: | ||
| 393 | if (rspi->dma_width_16bit) | ||
| 394 | kfree(buf); | ||
| 395 | |||
| 396 | return ret; | ||
| 397 | } | ||
| 398 | |||
| 399 | static void rspi_receive_init(struct rspi_data *rspi) | ||
| 270 | { | 400 | { |
| 271 | int remain = t->len; | ||
| 272 | u8 *data; | ||
| 273 | unsigned char spsr; | 401 | unsigned char spsr; |
| 274 | 402 | ||
| 275 | spsr = rspi_read8(rspi, RSPI_SPSR); | 403 | spsr = rspi_read8(rspi, RSPI_SPSR); |
| @@ -278,6 +406,15 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, | |||
| 278 | if (spsr & SPSR_OVRF) | 406 | if (spsr & SPSR_OVRF) |
| 279 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, | 407 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, |
| 280 | RSPI_SPCR); | 408 | RSPI_SPCR); |
| 409 | } | ||
| 410 | |||
| 411 | static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, | ||
| 412 | struct spi_transfer *t) | ||
| 413 | { | ||
| 414 | int remain = t->len; | ||
| 415 | u8 *data; | ||
| 416 | |||
| 417 | rspi_receive_init(rspi); | ||
| 281 | 418 | ||
| 282 | data = (u8 *)t->rx_buf; | 419 | data = (u8 *)t->rx_buf; |
| 283 | while (remain > 0) { | 420 | while (remain > 0) { |
| @@ -307,6 +444,120 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, | |||
| 307 | return 0; | 444 | return 0; |
| 308 | } | 445 | } |
| 309 | 446 | ||
| 447 | static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) | ||
| 448 | { | ||
| 449 | struct scatterlist sg, sg_dummy; | ||
| 450 | void *dummy = NULL, *rx_buf = NULL; | ||
| 451 | struct dma_async_tx_descriptor *desc, *desc_dummy; | ||
| 452 | unsigned len; | ||
| 453 | int ret = 0; | ||
| 454 | |||
| 455 | if (rspi->dma_width_16bit) { | ||
| 456 | /* | ||
| 457 | * If DMAC bus width is 16-bit, the driver allocates a dummy | ||
| 458 | * buffer. And, finally the driver converts the DMAC data into | ||
| 459 | * actual data as the following | ||
