| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * IMG SPFI controller driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2007,2008,2013 Imagination Technologies Ltd. |
|---|
| 5 | 6 | * Copyright (C) 2014 Google, Inc. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 9 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 10 | 7 | */ |
|---|
| 11 | 8 | |
|---|
| 12 | 9 | #include <linux/clk.h> |
|---|
| 13 | 10 | #include <linux/delay.h> |
|---|
| 14 | 11 | #include <linux/dmaengine.h> |
|---|
| 15 | | -#include <linux/gpio.h> |
|---|
| 16 | 12 | #include <linux/interrupt.h> |
|---|
| 17 | 13 | #include <linux/io.h> |
|---|
| 18 | 14 | #include <linux/irq.h> |
|---|
| .. | .. |
|---|
| 103 | 99 | struct dma_chan *tx_ch; |
|---|
| 104 | 100 | bool tx_dma_busy; |
|---|
| 105 | 101 | bool rx_dma_busy; |
|---|
| 106 | | -}; |
|---|
| 107 | | - |
|---|
| 108 | | -struct img_spfi_device_data { |
|---|
| 109 | | - bool gpio_requested; |
|---|
| 110 | 102 | }; |
|---|
| 111 | 103 | |
|---|
| 112 | 104 | static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) |
|---|
| .. | .. |
|---|
| 445 | 437 | return 0; |
|---|
| 446 | 438 | } |
|---|
| 447 | 439 | |
|---|
| 448 | | -static int img_spfi_setup(struct spi_device *spi) |
|---|
| 449 | | -{ |
|---|
| 450 | | - int ret = -EINVAL; |
|---|
| 451 | | - struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); |
|---|
| 452 | | - |
|---|
| 453 | | - if (!spfi_data) { |
|---|
| 454 | | - spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL); |
|---|
| 455 | | - if (!spfi_data) |
|---|
| 456 | | - return -ENOMEM; |
|---|
| 457 | | - spfi_data->gpio_requested = false; |
|---|
| 458 | | - spi_set_ctldata(spi, spfi_data); |
|---|
| 459 | | - } |
|---|
| 460 | | - if (!spfi_data->gpio_requested) { |
|---|
| 461 | | - ret = gpio_request_one(spi->cs_gpio, |
|---|
| 462 | | - (spi->mode & SPI_CS_HIGH) ? |
|---|
| 463 | | - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, |
|---|
| 464 | | - dev_name(&spi->dev)); |
|---|
| 465 | | - if (ret) |
|---|
| 466 | | - dev_err(&spi->dev, "can't request chipselect gpio %d\n", |
|---|
| 467 | | - spi->cs_gpio); |
|---|
| 468 | | - else |
|---|
| 469 | | - spfi_data->gpio_requested = true; |
|---|
| 470 | | - } else { |
|---|
| 471 | | - if (gpio_is_valid(spi->cs_gpio)) { |
|---|
| 472 | | - int mode = ((spi->mode & SPI_CS_HIGH) ? |
|---|
| 473 | | - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); |
|---|
| 474 | | - |
|---|
| 475 | | - ret = gpio_direction_output(spi->cs_gpio, mode); |
|---|
| 476 | | - if (ret) |
|---|
| 477 | | - dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", |
|---|
| 478 | | - spi->cs_gpio, ret); |
|---|
| 479 | | - } |
|---|
| 480 | | - } |
|---|
| 481 | | - return ret; |
|---|
| 482 | | -} |
|---|
| 483 | | - |
|---|
| 484 | | -static void img_spfi_cleanup(struct spi_device *spi) |
|---|
| 485 | | -{ |
|---|
| 486 | | - struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); |
|---|
| 487 | | - |
|---|
| 488 | | - if (spfi_data) { |
|---|
| 489 | | - if (spfi_data->gpio_requested) |
|---|
| 490 | | - gpio_free(spi->cs_gpio); |
|---|
| 491 | | - kfree(spfi_data); |
|---|
| 492 | | - spi_set_ctldata(spi, NULL); |
|---|
| 493 | | - } |
|---|
| 494 | | -} |
|---|
| 495 | | - |
|---|
| 496 | 440 | static void img_spfi_config(struct spi_master *master, struct spi_device *spi, |
|---|
| 497 | 441 | struct spi_transfer *xfer) |
|---|
| 498 | 442 | { |
|---|
| .. | .. |
|---|
| 662 | 606 | master->max_speed_hz = max_speed_hz; |
|---|
| 663 | 607 | } |
|---|
| 664 | 608 | |
|---|
| 665 | | - master->setup = img_spfi_setup; |
|---|
| 666 | | - master->cleanup = img_spfi_cleanup; |
|---|
| 667 | 609 | master->transfer_one = img_spfi_transfer_one; |
|---|
| 668 | 610 | master->prepare_message = img_spfi_prepare; |
|---|
| 669 | 611 | master->unprepare_message = img_spfi_unprepare; |
|---|
| 670 | 612 | master->handle_err = img_spfi_handle_err; |
|---|
| 613 | + master->use_gpio_descriptors = true; |
|---|
| 671 | 614 | |
|---|
| 672 | | - spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx"); |
|---|
| 673 | | - spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx"); |
|---|
| 615 | + spfi->tx_ch = dma_request_chan(spfi->dev, "tx"); |
|---|
| 616 | + if (IS_ERR(spfi->tx_ch)) { |
|---|
| 617 | + ret = PTR_ERR(spfi->tx_ch); |
|---|
| 618 | + spfi->tx_ch = NULL; |
|---|
| 619 | + if (ret == -EPROBE_DEFER) |
|---|
| 620 | + goto disable_pm; |
|---|
| 621 | + } |
|---|
| 622 | + |
|---|
| 623 | + spfi->rx_ch = dma_request_chan(spfi->dev, "rx"); |
|---|
| 624 | + if (IS_ERR(spfi->rx_ch)) { |
|---|
| 625 | + ret = PTR_ERR(spfi->rx_ch); |
|---|
| 626 | + spfi->rx_ch = NULL; |
|---|
| 627 | + if (ret == -EPROBE_DEFER) |
|---|
| 628 | + goto disable_pm; |
|---|
| 629 | + } |
|---|
| 630 | + |
|---|
| 674 | 631 | if (!spfi->tx_ch || !spfi->rx_ch) { |
|---|
| 675 | 632 | if (spfi->tx_ch) |
|---|
| 676 | 633 | dma_release_channel(spfi->tx_ch); |
|---|
| .. | .. |
|---|
| 774 | 731 | int ret; |
|---|
| 775 | 732 | |
|---|
| 776 | 733 | ret = pm_runtime_get_sync(dev); |
|---|
| 777 | | - if (ret) { |
|---|
| 734 | + if (ret < 0) { |
|---|
| 778 | 735 | pm_runtime_put_noidle(dev); |
|---|
| 779 | 736 | return ret; |
|---|
| 780 | 737 | } |
|---|