diff options
Diffstat (limited to 'drivers/spi/spi-ti-qspi.c')
-rw-r--r-- | drivers/spi/spi-ti-qspi.c | 138 |
1 files changed, 87 insertions, 51 deletions
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0b71270fbf67..3d09265b5133 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c | |||
@@ -46,6 +46,8 @@ struct ti_qspi { | |||
46 | 46 | ||
47 | struct spi_master *master; | 47 | struct spi_master *master; |
48 | void __iomem *base; | 48 | void __iomem *base; |
49 | void __iomem *ctrl_base; | ||
50 | void __iomem *mmap_base; | ||
49 | struct clk *fclk; | 51 | struct clk *fclk; |
50 | struct device *dev; | 52 | struct device *dev; |
51 | 53 | ||
@@ -54,6 +56,8 @@ struct ti_qspi { | |||
54 | u32 spi_max_frequency; | 56 | u32 spi_max_frequency; |
55 | u32 cmd; | 57 | u32 cmd; |
56 | u32 dc; | 58 | u32 dc; |
59 | |||
60 | bool ctrl_mod; | ||
57 | }; | 61 | }; |
58 | 62 | ||
59 | #define QSPI_PID (0x0) | 63 | #define QSPI_PID (0x0) |
@@ -161,7 +165,7 @@ static int ti_qspi_setup(struct spi_device *spi) | |||
161 | qspi->spi_max_frequency, clk_div); | 165 | qspi->spi_max_frequency, clk_div); |
162 | 166 | ||
163 | ret = pm_runtime_get_sync(qspi->dev); | 167 | ret = pm_runtime_get_sync(qspi->dev); |
164 | if (ret) { | 168 | if (ret < 0) { |
165 | dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); | 169 | dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); |
166 | return ret; | 170 | return ret; |
167 | } | 171 | } |
@@ -204,53 +208,36 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) | |||
204 | txbuf = t->tx_buf; | 208 | txbuf = t->tx_buf; |
205 | cmd = qspi->cmd | QSPI_WR_SNGL; | 209 | cmd = qspi->cmd | QSPI_WR_SNGL; |
206 | count = t->len; | 210 | count = t->len; |
207 | wlen = t->bits_per_word; | 211 | wlen = t->bits_per_word >> 3; /* in bytes */ |
208 | 212 | ||
209 | while (count) { | 213 | while (count) { |
210 | switch (wlen) { | 214 | switch (wlen) { |
211 | case 8: | 215 | case 1: |
212 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", | 216 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", |
213 | cmd, qspi->dc, *txbuf); | 217 | cmd, qspi->dc, *txbuf); |
214 | writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); | 218 | writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); |
215 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); | ||
216 | ret = wait_for_completion_timeout(&qspi->transfer_complete, | ||
217 | QSPI_COMPLETION_TIMEOUT); | ||
218 | if (ret == 0) { | ||
219 | dev_err(qspi->dev, "write timed out\n"); | ||
220 | return -ETIMEDOUT; | ||
221 | } | ||
222 | txbuf += 1; | ||
223 | count -= 1; | ||
224 | break; | 219 | break; |
225 | case 16: | 220 | case 2: |
226 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", | 221 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", |
227 | cmd, qspi->dc, *txbuf); | 222 | cmd, qspi->dc, *txbuf); |
228 | writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); | 223 | writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); |
229 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); | ||
230 | ret = wait_for_completion_timeout(&qspi->transfer_complete, | ||
231 | QSPI_COMPLETION_TIMEOUT); | ||
232 | if (ret == 0) { | ||
233 | dev_err(qspi->dev, "write timed out\n"); | ||
234 | return -ETIMEDOUT; | ||
235 | } | ||
236 | txbuf += 2; | ||
237 | count -= 2; | ||
238 | break; | 224 | break; |
239 | case 32: | 225 | case 4: |
240 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", | 226 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", |
241 | cmd, qspi->dc, *txbuf); | 227 | cmd, qspi->dc, *txbuf); |
242 | writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); | 228 | writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); |
243 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); | ||
244 | ret = wait_for_completion_timeout(&qspi->transfer_complete, | ||
245 | QSPI_COMPLETION_TIMEOUT); | ||
246 | if (ret == 0) { | ||
247 | dev_err(qspi->dev, "write timed out\n"); | ||
248 | return -ETIMEDOUT; | ||
249 | } | ||
250 | txbuf += 4; | ||
251 | count -= 4; | ||
252 | break; | 229 | break; |
253 | } | 230 | } |
231 | |||
232 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); | ||
233 | ret = wait_for_completion_timeout(&qspi->transfer_complete, | ||
234 | QSPI_COMPLETION_TIMEOUT); | ||
235 | if (ret == 0) { | ||
236 | dev_err(qspi->dev, "write timed out\n"); | ||
237 | return -ETIMEDOUT; | ||
238 | } | ||
239 | txbuf += wlen; | ||
240 | count -= wlen; | ||
254 | } | 241 | } |
255 | 242 | ||
256 | return 0; | 243 | return 0; |
@@ -276,7 +263,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) | |||
276 | break; | 263 | break; |
277 | } | 264 | } |
278 | count = t->len; | 265 | count = t->len; |
279 | wlen = t->bits_per_word; | 266 | wlen = t->bits_per_word >> 3; /* in bytes */ |
280 | 267 | ||
281 | while (count) { | 268 | while (count) { |
282 | dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); | 269 | dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); |
@@ -288,22 +275,18 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) | |||
288 | return -ETIMEDOUT; | 275 | return -ETIMEDOUT; |
289 | } | 276 | } |
290 | switch (wlen) { | 277 | switch (wlen) { |
291 | case 8: | 278 | case 1: |
292 | *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); | 279 | *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); |
293 | rxbuf += 1; | ||
294 | count -= 1; | ||
295 | break; | 280 | break; |
296 | case 16: | 281 | case 2: |
297 | *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); | 282 | *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); |
298 | rxbuf += 2; | ||
299 | count -= 2; | ||
300 | break; | 283 | break; |
301 | case 32: | 284 | case 4: |
302 | *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); | 285 | *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); |
303 | rxbuf += 4; | ||
304 | count -= 4; | ||
305 | break; | 286 | break; |
306 | } | 287 | } |
288 | rxbuf += wlen; | ||
289 | count -= wlen; | ||
307 | } | 290 | } |
308 | 291 | ||
309 | return 0; | 292 | return 0; |
@@ -417,10 +400,8 @@ out: | |||
417 | static int ti_qspi_runtime_resume(struct device *dev) | 400 | static int ti_qspi_runtime_resume(struct device *dev) |
418 | { | 401 | { |
419 | struct ti_qspi *qspi; | 402 | struct ti_qspi *qspi; |
420 | struct spi_master *master; | ||
421 | 403 | ||
422 | master = dev_get_drvdata(dev); | 404 | qspi = dev_get_drvdata(dev); |
423 | qspi = spi_master_get_devdata(master); | ||
424 | ti_qspi_restore_ctx(qspi); | 405 | ti_qspi_restore_ctx(qspi); |
425 | 406 | ||
426 | return 0; | 407 | return 0; |
@@ -437,7 +418,7 @@ static int ti_qspi_probe(struct platform_device *pdev) | |||
437 | { | 418 | { |
438 | struct ti_qspi *qspi; | 419 | struct ti_qspi *qspi; |
439 | struct spi_master *master; | 420 | struct spi_master *master; |
440 | struct resource *r; | 421 | struct resource *r, *res_ctrl, *res_mmap; |
441 | struct device_node *np = pdev->dev.of_node; | 422 | struct device_node *np = pdev->dev.of_node; |
442 | u32 max_freq; | 423 | u32 max_freq; |
443 | int ret = 0, num_cs, irq; | 424 | int ret = 0, num_cs, irq; |
@@ -459,13 +440,40 @@ static int ti_qspi_probe(struct platform_device *pdev) | |||
459 | if (!of_property_read_u32(np, "num-cs", &num_cs)) | 440 | if (!of_property_read_u32(np, "num-cs", &num_cs)) |
460 | master->num_chipselect = num_cs; | 441 | master->num_chipselect = num_cs; |
461 | 442 | ||
462 | platform_set_drvdata(pdev, master); | ||
463 | |||
464 | qspi = spi_master_get_devdata(master); | 443 | qspi = spi_master_get_devdata(master); |
465 | qspi->master = master; | 444 | qspi->master = master; |
466 | qspi->dev = &pdev->dev; | 445 | qspi->dev = &pdev->dev; |
446 | platform_set_drvdata(pdev, qspi); | ||
447 | |||
448 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); | ||
449 | if (r == NULL) { | ||
450 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
451 | if (r == NULL) { | ||
452 | dev_err(&pdev->dev, "missing platform data\n"); | ||
453 | return -ENODEV; | ||
454 | } | ||
455 | } | ||
467 | 456 | ||
468 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 457 | res_mmap = platform_get_resource_byname(pdev, |
458 | IORESOURCE_MEM, "qspi_mmap"); | ||
459 | if (res_mmap == NULL) { | ||
460 | res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
461 | if (res_mmap == NULL) { | ||
462 | dev_err(&pdev->dev, | ||
463 | "memory mapped resource not required\n"); | ||
464 | return -ENODEV; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | res_ctrl = platform_get_resource_byname(pdev, | ||
469 | IORESOURCE_MEM, "qspi_ctrlmod"); | ||
470 | if (res_ctrl == NULL) { | ||
471 | res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); | ||
472 | if (res_ctrl == NULL) { | ||
473 | dev_dbg(&pdev->dev, | ||
474 | "control module resources not required\n"); | ||
475 | } | ||
476 | } | ||
469 | 477 | ||
470 | irq = platform_get_irq(pdev, 0); | 478 | irq = platform_get_irq(pdev, 0); |
471 | if (irq < 0) { | 479 | if (irq < 0) { |
@@ -481,6 +489,23 @@ static int ti_qspi_probe(struct platform_device *pdev) | |||
481 | goto free_master; | 489 | goto free_master; |
482 | } | 490 | } |
483 | 491 | ||
492 | if (res_ctrl) { | ||
493 | qspi->ctrl_mod = true; | ||
494 | qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); | ||
495 | if (IS_ERR(qspi->ctrl_base)) { | ||
496 | ret = PTR_ERR(qspi->ctrl_base); | ||
497 | goto free_master; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | if (res_mmap) { | ||
502 | qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); | ||
503 | if (IS_ERR(qspi->mmap_base)) { | ||
504 | ret = PTR_ERR(qspi->mmap_base); | ||
505 | goto free_master; | ||
506 | } | ||
507 | } | ||
508 | |||
484 | ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, | 509 | ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, |
485 | dev_name(&pdev->dev), qspi); | 510 | dev_name(&pdev->dev), qspi); |
486 | if (ret < 0) { | 511 | if (ret < 0) { |
@@ -517,10 +542,20 @@ free_master: | |||
517 | 542 | ||
518 | static int ti_qspi_remove(struct platform_device *pdev) | 543 | static int ti_qspi_remove(struct platform_device *pdev) |
519 | { | 544 | { |
520 | struct ti_qspi *qspi = platform_get_drvdata(pdev); | 545 | struct ti_qspi *qspi = platform_get_drvdata(pdev); |
546 | int ret; | ||
547 | |||
548 | ret = pm_runtime_get_sync(qspi->dev); | ||
549 | if (ret < 0) { | ||
550 | dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); | ||
551 | return ret; | ||
552 | } | ||
521 | 553 | ||
522 | ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); | 554 | ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); |
523 | 555 | ||
556 | pm_runtime_put(qspi->dev); | ||
557 | pm_runtime_disable(&pdev->dev); | ||
558 | |||
524 | return 0; | 559 | return 0; |
525 | } | 560 | } |
526 | 561 | ||
@@ -532,7 +567,7 @@ static struct platform_driver ti_qspi_driver = { | |||
532 | .probe = ti_qspi_probe, | 567 | .probe = ti_qspi_probe, |
533 | .remove = ti_qspi_remove, | 568 | .remove = ti_qspi_remove, |
534 | .driver = { | 569 | .driver = { |
535 | .name = "ti,dra7xxx-qspi", | 570 | .name = "ti-qspi", |
536 | .owner = THIS_MODULE, | 571 | .owner = THIS_MODULE, |
537 | .pm = &ti_qspi_pm_ops, | 572 | .pm = &ti_qspi_pm_ops, |
538 | .of_match_table = ti_qspi_match, | 573 | .of_match_table = ti_qspi_match, |
@@ -544,3 +579,4 @@ module_platform_driver(ti_qspi_driver); | |||
544 | MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); | 579 | MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); |
545 | MODULE_LICENSE("GPL v2"); | 580 | MODULE_LICENSE("GPL v2"); |
546 | MODULE_DESCRIPTION("TI QSPI controller driver"); | 581 | MODULE_DESCRIPTION("TI QSPI controller driver"); |
582 | MODULE_ALIAS("platform:ti-qspi"); | ||