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

spi/rspi: add dmaengine support

This patch adds dmaengine supporting using sh_dma driver. The module
receives data by DMAC, it also needs TX DMAC to generate SPI's clocks.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

authored by

Shimoda, Yoshihiro and committed by
Grant Likely
a3633fe7 d195f7be

+345 -6
+314 -6
drivers/spi/spi-rspi.c
··· 31 31 #include <linux/platform_device.h> 32 32 #include <linux/io.h> 33 33 #include <linux/clk.h> 34 + #include <linux/dmaengine.h> 35 + #include <linux/dma-mapping.h> 36 + #include <linux/sh_dma.h> 34 37 #include <linux/spi/spi.h> 38 + #include <linux/spi/rspi.h> 35 39 36 40 #define RSPI_SPCR 0x00 37 41 #define RSPI_SSLP 0x01 ··· 145 141 spinlock_t lock; 146 142 struct clk *clk; 147 143 unsigned char spsr; 144 + 145 + /* for dmaengine */ 146 + struct sh_dmae_slave dma_tx; 147 + struct sh_dmae_slave dma_rx; 148 + struct dma_chan *chan_tx; 149 + struct dma_chan *chan_rx; 150 + int irq; 151 + 152 + unsigned dma_width_16bit:1; 153 + unsigned dma_callbacked:1; 148 154 }; 149 155 150 156 static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset) ··· 279 265 return 0; 280 266 } 281 267 282 - static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, 283 - struct spi_transfer *t) 268 + static void rspi_dma_complete(void *arg) 284 269 { 285 - int remain = t->len; 286 - u8 *data; 270 + struct rspi_data *rspi = arg; 271 + 272 + rspi->dma_callbacked = 1; 273 + wake_up_interruptible(&rspi->wait); 274 + } 275 + 276 + static int rspi_dma_map_sg(struct scatterlist *sg, void *buf, unsigned len, 277 + struct dma_chan *chan, 278 + enum dma_transfer_direction dir) 279 + { 280 + sg_init_table(sg, 1); 281 + sg_set_buf(sg, buf, len); 282 + sg_dma_len(sg) = len; 283 + return dma_map_sg(chan->device->dev, sg, 1, dir); 284 + } 285 + 286 + static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan, 287 + enum dma_transfer_direction dir) 288 + { 289 + dma_unmap_sg(chan->device->dev, sg, 1, dir); 290 + } 291 + 292 + static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len) 293 + { 294 + u16 *dst = buf; 295 + const u8 *src = data; 296 + 297 + while (len) { 298 + *dst++ = (u16)(*src++); 299 + len--; 300 + } 301 + } 302 + 303 + static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len) 304 + { 305 + u8 *dst = buf; 306 + const u16 *src = data; 307 + 308 + while (len) { 309 + *dst++ = (u8)*src++; 310 + len--; 311 + } 312 + } 313 + 314 + static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) 315 + { 316 + struct scatterlist sg; 317 + void *buf = NULL; 318 + struct dma_async_tx_descriptor *desc; 319 + unsigned len; 320 + int ret = 0; 321 + 322 + if (rspi->dma_width_16bit) { 323 + /* 324 + * If DMAC bus width is 16-bit, the driver allocates a dummy 325 + * buffer. And, the driver converts original data into the 326 + * DMAC data as the following format: 327 + * original data: 1st byte, 2nd byte ... 328 + * DMAC data: 1st byte, dummy, 2nd byte, dummy ... 329 + */ 330 + len = t->len * 2; 331 + buf = kmalloc(len, GFP_KERNEL); 332 + if (!buf) 333 + return -ENOMEM; 334 + rspi_memory_to_8bit(buf, t->tx_buf, t->len); 335 + } else { 336 + len = t->len; 337 + buf = (void *)t->tx_buf; 338 + } 339 + 340 + if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) { 341 + ret = -EFAULT; 342 + goto end_nomap; 343 + } 344 + desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE, 345 + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 346 + if (!desc) { 347 + ret = -EIO; 348 + goto end; 349 + } 350 + 351 + /* 352 + * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be 353 + * called. So, this driver disables the IRQ while DMA transfer. 354 + */ 355 + disable_irq(rspi->irq); 356 + 357 + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); 358 + rspi_enable_irq(rspi, SPCR_SPTIE); 359 + rspi->dma_callbacked = 0; 360 + 361 + desc->callback = rspi_dma_complete; 362 + desc->callback_param = rspi; 363 + dmaengine_submit(desc); 364 + dma_async_issue_pending(rspi->chan_tx); 365 + 366 + ret = wait_event_interruptible_timeout(rspi->wait, 367 + rspi->dma_callbacked, HZ); 368 + if (ret > 0 && rspi->dma_callbacked) 369 + ret = 0; 370 + else if (!ret) 371 + ret = -ETIMEDOUT; 372 + rspi_disable_irq(rspi, SPCR_SPTIE); 373 + 374 + enable_irq(rspi->irq); 375 + 376 + end: 377 + rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); 378 + end_nomap: 379 + if (rspi->dma_width_16bit) 380 + kfree(buf); 381 + 382 + return ret; 383 + } 384 + 385 + static void rspi_receive_init(struct rspi_data *rspi) 386 + { 287 387 unsigned char spsr; 288 388 289 389 spsr = rspi_read8(rspi, RSPI_SPSR); ··· 406 278 if (spsr & SPSR_OVRF) 407 279 rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, 408 280 RSPI_SPCR); 281 + } 282 + 283 + static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, 284 + struct spi_transfer *t) 285 + { 286 + int remain = t->len; 287 + u8 *data; 288 + 289 + rspi_receive_init(rspi); 409 290 410 291 data = (u8 *)t->rx_buf; 411 292 while (remain > 0) { ··· 444 307 return 0; 445 308 } 446 309 310 + static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) 311 + { 312 + struct scatterlist sg, sg_dummy; 313 + void *dummy = NULL, *rx_buf = NULL; 314 + struct dma_async_tx_descriptor *desc, *desc_dummy; 315 + unsigned len; 316 + int ret = 0; 317 + 318 + if (rspi->dma_width_16bit) { 319 + /* 320 + * If DMAC bus width is 16-bit, the driver allocates a dummy 321 + * buffer. And, finally the driver converts the DMAC data into 322 + * actual data as the following format: 323 + * DMAC data: 1st byte, dummy, 2nd byte, dummy ... 324 + * actual data: 1st byte, 2nd byte ... 325 + */ 326 + len = t->len * 2; 327 + rx_buf = kmalloc(len, GFP_KERNEL); 328 + if (!rx_buf) 329 + return -ENOMEM; 330 + } else { 331 + len = t->len; 332 + rx_buf = t->rx_buf; 333 + } 334 + 335 + /* prepare dummy transfer to generate SPI clocks */ 336 + dummy = kzalloc(len, GFP_KERNEL); 337 + if (!dummy) { 338 + ret = -ENOMEM; 339 + goto end_nomap; 340 + } 341 + if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx, 342 + DMA_TO_DEVICE)) { 343 + ret = -EFAULT; 344 + goto end_nomap; 345 + } 346 + desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1, 347 + DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 348 + if (!desc_dummy) { 349 + ret = -EIO; 350 + goto end_dummy_mapped; 351 + } 352 + 353 + /* prepare receive transfer */ 354 + if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx, 355 + DMA_FROM_DEVICE)) { 356 + ret = -EFAULT; 357 + goto end_dummy_mapped; 358 + 359 + } 360 + desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE, 361 + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 362 + if (!desc) { 363 + ret = -EIO; 364 + goto end; 365 + } 366 + 367 + rspi_receive_init(rspi); 368 + 369 + /* 370 + * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be 371 + * called. So, this driver disables the IRQ while DMA transfer. 372 + */ 373 + disable_irq(rspi->irq); 374 + 375 + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); 376 + rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); 377 + rspi->dma_callbacked = 0; 378 + 379 + desc->callback = rspi_dma_complete; 380 + desc->callback_param = rspi; 381 + dmaengine_submit(desc); 382 + dma_async_issue_pending(rspi->chan_rx); 383 + 384 + desc_dummy->callback = NULL; /* No callback */ 385 + dmaengine_submit(desc_dummy); 386 + dma_async_issue_pending(rspi->chan_tx); 387 + 388 + ret = wait_event_interruptible_timeout(rspi->wait, 389 + rspi->dma_callbacked, HZ); 390 + if (ret > 0 && rspi->dma_callbacked) 391 + ret = 0; 392 + else if (!ret) 393 + ret = -ETIMEDOUT; 394 + rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); 395 + 396 + enable_irq(rspi->irq); 397 + 398 + end: 399 + rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); 400 + end_dummy_mapped: 401 + rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE); 402 + end_nomap: 403 + if (rspi->dma_width_16bit) { 404 + if (!ret) 405 + rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len); 406 + kfree(rx_buf); 407 + } 408 + kfree(dummy); 409 + 410 + return ret; 411 + } 412 + 413 + static int rspi_is_dma(struct rspi_data *rspi, struct spi_transfer *t) 414 + { 415 + if (t->tx_buf && rspi->chan_tx) 416 + return 1; 417 + /* If the module receives data by DMAC, it also needs TX DMAC */ 418 + if (t->rx_buf && rspi->chan_tx && rspi->chan_rx) 419 + return 1; 420 + 421 + return 0; 422 + } 423 + 447 424 static void rspi_work(struct work_struct *work) 448 425 { 449 426 struct rspi_data *rspi = container_of(work, struct rspi_data, ws); ··· 576 325 577 326 list_for_each_entry(t, &mesg->transfers, transfer_list) { 578 327 if (t->tx_buf) { 579 - ret = rspi_send_pio(rspi, mesg, t); 328 + if (rspi_is_dma(rspi, t)) 329 + ret = rspi_send_dma(rspi, t); 330 + else 331 + ret = rspi_send_pio(rspi, mesg, t); 580 332 if (ret < 0) 581 333 goto error; 582 334 } 583 335 if (t->rx_buf) { 584 - ret = rspi_receive_pio(rspi, mesg, t); 336 + if (rspi_is_dma(rspi, t)) 337 + ret = rspi_receive_dma(rspi, t); 338 + else 339 + ret = rspi_receive_pio(rspi, mesg, t); 585 340 if (ret < 0) 586 341 goto error; 587 342 } ··· 663 406 return ret; 664 407 } 665 408 409 + static bool rspi_filter(struct dma_chan *chan, void *filter_param) 410 + { 411 + chan->private = filter_param; 412 + return true; 413 + } 414 + 415 + static void __devinit rspi_request_dma(struct rspi_data *rspi, 416 + struct platform_device *pdev) 417 + { 418 + struct rspi_plat_data *rspi_pd = pdev->dev.platform_data; 419 + dma_cap_mask_t mask; 420 + 421 + if (!rspi_pd) 422 + return; 423 + 424 + rspi->dma_width_16bit = rspi_pd->dma_width_16bit; 425 + 426 + /* If the module receives data by DMAC, it also needs TX DMAC */ 427 + if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { 428 + dma_cap_zero(mask); 429 + dma_cap_set(DMA_SLAVE, mask); 430 + rspi->dma_rx.slave_id = rspi_pd->dma_rx_id; 431 + rspi->chan_rx = dma_request_channel(mask, rspi_filter, 432 + &rspi->dma_rx); 433 + if (rspi->chan_rx) 434 + dev_info(&pdev->dev, "Use DMA when rx.\n"); 435 + } 436 + if (rspi_pd->dma_tx_id) { 437 + dma_cap_zero(mask); 438 + dma_cap_set(DMA_SLAVE, mask); 439 + rspi->dma_tx.slave_id = rspi_pd->dma_tx_id; 440 + rspi->chan_tx = dma_request_channel(mask, rspi_filter, 441 + &rspi->dma_tx); 442 + if (rspi->chan_tx) 443 + dev_info(&pdev->dev, "Use DMA when tx\n"); 444 + } 445 + } 446 + 447 + static void __devexit rspi_release_dma(struct rspi_data *rspi) 448 + { 449 + if (rspi->chan_tx) 450 + dma_release_channel(rspi->chan_tx); 451 + if (rspi->chan_rx) 452 + dma_release_channel(rspi->chan_rx); 453 + } 454 + 666 455 static int __devexit rspi_remove(struct platform_device *pdev) 667 456 { 668 457 struct rspi_data *rspi = dev_get_drvdata(&pdev->dev); 669 458 670 459 spi_unregister_master(rspi->master); 460 + rspi_release_dma(rspi); 671 461 free_irq(platform_get_irq(pdev, 0), rspi); 672 462 clk_put(rspi->clk); 673 463 iounmap(rspi->addr); ··· 787 483 goto error3; 788 484 } 789 485 486 + rspi->irq = irq; 487 + rspi_request_dma(rspi, pdev); 488 + 790 489 ret = spi_register_master(master); 791 490 if (ret < 0) { 792 491 dev_err(&pdev->dev, "spi_register_master error.\n"); ··· 801 494 return 0; 802 495 803 496 error4: 497 + rspi_release_dma(rspi); 804 498 free_irq(irq, rspi); 805 499 error3: 806 500 clk_put(rspi->clk);
+31
include/linux/spi/rspi.h
··· 1 + /* 2 + * Renesas SPI driver 3 + * 4 + * Copyright (C) 2012 Renesas Solutions Corp. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; version 2 of the License. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 + * 19 + */ 20 + 21 + #ifndef __LINUX_SPI_RENESAS_SPI_H__ 22 + #define __LINUX_SPI_RENESAS_SPI_H__ 23 + 24 + struct rspi_plat_data { 25 + unsigned int dma_tx_id; 26 + unsigned int dma_rx_id; 27 + 28 + unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */ 29 + }; 30 + 31 + #endif