| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2008-2014, The Linux foundation. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License rev 2 and |
|---|
| 6 | | - * only rev 2 as published by the free Software foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | 6 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 281 | 273 | writel_relaxed(QUP_OP_IN_SERVICE_FLAG, |
|---|
| 282 | 274 | controller->base + QUP_OPERATIONAL); |
|---|
| 283 | 275 | |
|---|
| 276 | + if (!remainder) |
|---|
| 277 | + goto exit; |
|---|
| 278 | + |
|---|
| 284 | 279 | if (is_block_mode) { |
|---|
| 285 | 280 | num_words = (remainder > words_per_block) ? |
|---|
| 286 | 281 | words_per_block : remainder; |
|---|
| .. | .. |
|---|
| 310 | 305 | * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be |
|---|
| 311 | 306 | * present and this is used to determine if transaction is complete |
|---|
| 312 | 307 | */ |
|---|
| 313 | | - *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); |
|---|
| 314 | | - if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) |
|---|
| 315 | | - writel_relaxed(QUP_OP_IN_SERVICE_FLAG, |
|---|
| 316 | | - controller->base + QUP_OPERATIONAL); |
|---|
| 317 | | - |
|---|
| 308 | +exit: |
|---|
| 309 | + if (!remainder) { |
|---|
| 310 | + *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); |
|---|
| 311 | + if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) |
|---|
| 312 | + writel_relaxed(QUP_OP_IN_SERVICE_FLAG, |
|---|
| 313 | + controller->base + QUP_OPERATIONAL); |
|---|
| 314 | + } |
|---|
| 318 | 315 | } |
|---|
| 319 | 316 | |
|---|
| 320 | 317 | static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words) |
|---|
| .. | .. |
|---|
| 361 | 358 | /* ACK by clearing service flag */ |
|---|
| 362 | 359 | writel_relaxed(QUP_OP_OUT_SERVICE_FLAG, |
|---|
| 363 | 360 | controller->base + QUP_OPERATIONAL); |
|---|
| 361 | + |
|---|
| 362 | + /* make sure the interrupt is valid */ |
|---|
| 363 | + if (!remainder) |
|---|
| 364 | + return; |
|---|
| 364 | 365 | |
|---|
| 365 | 366 | if (is_block_mode) { |
|---|
| 366 | 367 | num_words = (remainder > words_per_block) ? |
|---|
| .. | .. |
|---|
| 575 | 576 | return 0; |
|---|
| 576 | 577 | } |
|---|
| 577 | 578 | |
|---|
| 579 | +static bool spi_qup_data_pending(struct spi_qup *controller) |
|---|
| 580 | +{ |
|---|
| 581 | + unsigned int remainder_tx, remainder_rx; |
|---|
| 582 | + |
|---|
| 583 | + remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) - |
|---|
| 584 | + controller->tx_bytes, controller->w_size); |
|---|
| 585 | + |
|---|
| 586 | + remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) - |
|---|
| 587 | + controller->rx_bytes, controller->w_size); |
|---|
| 588 | + |
|---|
| 589 | + return remainder_tx || remainder_rx; |
|---|
| 590 | +} |
|---|
| 591 | + |
|---|
| 578 | 592 | static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) |
|---|
| 579 | 593 | { |
|---|
| 580 | 594 | struct spi_qup *controller = dev_id; |
|---|
| 581 | 595 | u32 opflags, qup_err, spi_err; |
|---|
| 596 | + unsigned long flags; |
|---|
| 582 | 597 | int error = 0; |
|---|
| 583 | 598 | |
|---|
| 584 | 599 | qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); |
|---|
| .. | .. |
|---|
| 610 | 625 | error = -EIO; |
|---|
| 611 | 626 | } |
|---|
| 612 | 627 | |
|---|
| 628 | + spin_lock_irqsave(&controller->lock, flags); |
|---|
| 629 | + if (!controller->error) |
|---|
| 630 | + controller->error = error; |
|---|
| 631 | + spin_unlock_irqrestore(&controller->lock, flags); |
|---|
| 632 | + |
|---|
| 613 | 633 | if (spi_qup_is_dma_xfer(controller->mode)) { |
|---|
| 614 | 634 | writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); |
|---|
| 615 | 635 | } else { |
|---|
| .. | .. |
|---|
| 618 | 638 | |
|---|
| 619 | 639 | if (opflags & QUP_OP_OUT_SERVICE_FLAG) |
|---|
| 620 | 640 | spi_qup_write(controller); |
|---|
| 641 | + |
|---|
| 642 | + if (!spi_qup_data_pending(controller)) |
|---|
| 643 | + complete(&controller->done); |
|---|
| 621 | 644 | } |
|---|
| 622 | 645 | |
|---|
| 623 | | - if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) |
|---|
| 646 | + if (error) |
|---|
| 624 | 647 | complete(&controller->done); |
|---|
| 648 | + |
|---|
| 649 | + if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) { |
|---|
| 650 | + if (!spi_qup_is_dma_xfer(controller->mode)) { |
|---|
| 651 | + if (spi_qup_data_pending(controller)) |
|---|
| 652 | + return IRQ_HANDLED; |
|---|
| 653 | + } |
|---|
| 654 | + complete(&controller->done); |
|---|
| 655 | + } |
|---|
| 625 | 656 | |
|---|
| 626 | 657 | return IRQ_HANDLED; |
|---|
| 627 | 658 | } |
|---|
| .. | .. |
|---|
| 817 | 848 | { |
|---|
| 818 | 849 | struct spi_qup *controller = spi_master_get_devdata(master); |
|---|
| 819 | 850 | unsigned long timeout, flags; |
|---|
| 820 | | - int ret = -EIO; |
|---|
| 851 | + int ret; |
|---|
| 821 | 852 | |
|---|
| 822 | 853 | ret = spi_qup_io_prep(spi, xfer); |
|---|
| 823 | 854 | if (ret) |
|---|
| .. | .. |
|---|
| 842 | 873 | else |
|---|
| 843 | 874 | ret = spi_qup_do_pio(spi, xfer, timeout); |
|---|
| 844 | 875 | |
|---|
| 845 | | - if (ret) |
|---|
| 846 | | - goto exit; |
|---|
| 847 | | - |
|---|
| 848 | | -exit: |
|---|
| 849 | 876 | spi_qup_set_state(controller, QUP_STATE_RESET); |
|---|
| 850 | 877 | spin_lock_irqsave(&controller->lock, flags); |
|---|
| 851 | 878 | if (!ret) |
|---|
| .. | .. |
|---|
| 905 | 932 | int ret; |
|---|
| 906 | 933 | |
|---|
| 907 | 934 | /* allocate dma resources, if available */ |
|---|
| 908 | | - master->dma_rx = dma_request_slave_channel_reason(dev, "rx"); |
|---|
| 935 | + master->dma_rx = dma_request_chan(dev, "rx"); |
|---|
| 909 | 936 | if (IS_ERR(master->dma_rx)) |
|---|
| 910 | 937 | return PTR_ERR(master->dma_rx); |
|---|
| 911 | 938 | |
|---|
| 912 | | - master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); |
|---|
| 939 | + master->dma_tx = dma_request_chan(dev, "tx"); |
|---|
| 913 | 940 | if (IS_ERR(master->dma_tx)) { |
|---|
| 914 | 941 | ret = PTR_ERR(master->dma_tx); |
|---|
| 915 | 942 | goto err_tx; |
|---|
| .. | .. |
|---|
| 1003 | 1030 | return -ENXIO; |
|---|
| 1004 | 1031 | } |
|---|
| 1005 | 1032 | |
|---|
| 1006 | | - ret = clk_prepare_enable(cclk); |
|---|
| 1007 | | - if (ret) { |
|---|
| 1008 | | - dev_err(dev, "cannot enable core clock\n"); |
|---|
| 1009 | | - return ret; |
|---|
| 1010 | | - } |
|---|
| 1011 | | - |
|---|
| 1012 | | - ret = clk_prepare_enable(iclk); |
|---|
| 1013 | | - if (ret) { |
|---|
| 1014 | | - clk_disable_unprepare(cclk); |
|---|
| 1015 | | - dev_err(dev, "cannot enable iface clock\n"); |
|---|
| 1016 | | - return ret; |
|---|
| 1017 | | - } |
|---|
| 1018 | | - |
|---|
| 1019 | 1033 | master = spi_alloc_master(dev, sizeof(struct spi_qup)); |
|---|
| 1020 | 1034 | if (!master) { |
|---|
| 1021 | | - clk_disable_unprepare(cclk); |
|---|
| 1022 | | - clk_disable_unprepare(iclk); |
|---|
| 1023 | 1035 | dev_err(dev, "cannot allocate master\n"); |
|---|
| 1024 | 1036 | return -ENOMEM; |
|---|
| 1025 | 1037 | } |
|---|
| .. | .. |
|---|
| 1065 | 1077 | spin_lock_init(&controller->lock); |
|---|
| 1066 | 1078 | init_completion(&controller->done); |
|---|
| 1067 | 1079 | |
|---|
| 1080 | + ret = clk_prepare_enable(cclk); |
|---|
| 1081 | + if (ret) { |
|---|
| 1082 | + dev_err(dev, "cannot enable core clock\n"); |
|---|
| 1083 | + goto error_dma; |
|---|
| 1084 | + } |
|---|
| 1085 | + |
|---|
| 1086 | + ret = clk_prepare_enable(iclk); |
|---|
| 1087 | + if (ret) { |
|---|
| 1088 | + clk_disable_unprepare(cclk); |
|---|
| 1089 | + dev_err(dev, "cannot enable iface clock\n"); |
|---|
| 1090 | + goto error_dma; |
|---|
| 1091 | + } |
|---|
| 1092 | + |
|---|
| 1068 | 1093 | iomode = readl_relaxed(base + QUP_IO_M_MODES); |
|---|
| 1069 | 1094 | |
|---|
| 1070 | 1095 | size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode); |
|---|
| .. | .. |
|---|
| 1094 | 1119 | ret = spi_qup_set_state(controller, QUP_STATE_RESET); |
|---|
| 1095 | 1120 | if (ret) { |
|---|
| 1096 | 1121 | dev_err(dev, "cannot set RESET state\n"); |
|---|
| 1097 | | - goto error_dma; |
|---|
| 1122 | + goto error_clk; |
|---|
| 1098 | 1123 | } |
|---|
| 1099 | 1124 | |
|---|
| 1100 | 1125 | writel_relaxed(0, base + QUP_OPERATIONAL); |
|---|
| .. | .. |
|---|
| 1118 | 1143 | ret = devm_request_irq(dev, irq, spi_qup_qup_irq, |
|---|
| 1119 | 1144 | IRQF_TRIGGER_HIGH, pdev->name, controller); |
|---|
| 1120 | 1145 | if (ret) |
|---|
| 1121 | | - goto error_dma; |
|---|
| 1146 | + goto error_clk; |
|---|
| 1122 | 1147 | |
|---|
| 1123 | 1148 | pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); |
|---|
| 1124 | 1149 | pm_runtime_use_autosuspend(dev); |
|---|
| .. | .. |
|---|
| 1133 | 1158 | |
|---|
| 1134 | 1159 | disable_pm: |
|---|
| 1135 | 1160 | pm_runtime_disable(&pdev->dev); |
|---|
| 1161 | +error_clk: |
|---|
| 1162 | + clk_disable_unprepare(cclk); |
|---|
| 1163 | + clk_disable_unprepare(iclk); |
|---|
| 1136 | 1164 | error_dma: |
|---|
| 1137 | 1165 | spi_qup_release_dma(master); |
|---|
| 1138 | 1166 | error: |
|---|
| 1139 | | - clk_disable_unprepare(cclk); |
|---|
| 1140 | | - clk_disable_unprepare(iclk); |
|---|
| 1141 | 1167 | spi_master_put(master); |
|---|
| 1142 | 1168 | return ret; |
|---|
| 1143 | 1169 | } |
|---|
| .. | .. |
|---|
| 1172 | 1198 | return ret; |
|---|
| 1173 | 1199 | |
|---|
| 1174 | 1200 | ret = clk_prepare_enable(controller->cclk); |
|---|
| 1175 | | - if (ret) |
|---|
| 1201 | + if (ret) { |
|---|
| 1202 | + clk_disable_unprepare(controller->iclk); |
|---|
| 1176 | 1203 | return ret; |
|---|
| 1204 | + } |
|---|
| 1177 | 1205 | |
|---|
| 1178 | 1206 | /* Disable clocks auto gaiting */ |
|---|
| 1179 | 1207 | config = readl_relaxed(controller->base + QUP_CONFIG); |
|---|
| .. | .. |
|---|
| 1219 | 1247 | return ret; |
|---|
| 1220 | 1248 | |
|---|
| 1221 | 1249 | ret = clk_prepare_enable(controller->cclk); |
|---|
| 1222 | | - if (ret) |
|---|
| 1250 | + if (ret) { |
|---|
| 1251 | + clk_disable_unprepare(controller->iclk); |
|---|
| 1223 | 1252 | return ret; |
|---|
| 1253 | + } |
|---|
| 1224 | 1254 | |
|---|
| 1225 | 1255 | ret = spi_qup_set_state(controller, QUP_STATE_RESET); |
|---|
| 1226 | 1256 | if (ret) |
|---|
| 1227 | | - return ret; |
|---|
| 1257 | + goto disable_clk; |
|---|
| 1228 | 1258 | |
|---|
| 1229 | | - return spi_master_resume(master); |
|---|
| 1259 | + ret = spi_master_resume(master); |
|---|
| 1260 | + if (ret) |
|---|
| 1261 | + goto disable_clk; |
|---|
| 1262 | + |
|---|
| 1263 | + return 0; |
|---|
| 1264 | + |
|---|
| 1265 | +disable_clk: |
|---|
| 1266 | + clk_disable_unprepare(controller->cclk); |
|---|
| 1267 | + clk_disable_unprepare(controller->iclk); |
|---|
| 1268 | + return ret; |
|---|
| 1230 | 1269 | } |
|---|
| 1231 | 1270 | #endif /* CONFIG_PM_SLEEP */ |
|---|
| 1232 | 1271 | |
|---|
| .. | .. |
|---|
| 1237 | 1276 | int ret; |
|---|
| 1238 | 1277 | |
|---|
| 1239 | 1278 | ret = pm_runtime_get_sync(&pdev->dev); |
|---|
| 1240 | | - if (ret < 0) |
|---|
| 1241 | | - return ret; |
|---|
| 1242 | 1279 | |
|---|
| 1243 | | - ret = spi_qup_set_state(controller, QUP_STATE_RESET); |
|---|
| 1244 | | - if (ret) |
|---|
| 1245 | | - return ret; |
|---|
| 1280 | + if (ret >= 0) { |
|---|
| 1281 | + ret = spi_qup_set_state(controller, QUP_STATE_RESET); |
|---|
| 1282 | + if (ret) |
|---|
| 1283 | + dev_warn(&pdev->dev, "failed to reset controller (%pe)\n", |
|---|
| 1284 | + ERR_PTR(ret)); |
|---|
| 1285 | + |
|---|
| 1286 | + clk_disable_unprepare(controller->cclk); |
|---|
| 1287 | + clk_disable_unprepare(controller->iclk); |
|---|
| 1288 | + } else { |
|---|
| 1289 | + dev_warn(&pdev->dev, "failed to resume, skip hw disable (%pe)\n", |
|---|
| 1290 | + ERR_PTR(ret)); |
|---|
| 1291 | + } |
|---|
| 1246 | 1292 | |
|---|
| 1247 | 1293 | spi_qup_release_dma(master); |
|---|
| 1248 | | - |
|---|
| 1249 | | - clk_disable_unprepare(controller->cclk); |
|---|
| 1250 | | - clk_disable_unprepare(controller->iclk); |
|---|
| 1251 | 1294 | |
|---|
| 1252 | 1295 | pm_runtime_put_noidle(&pdev->dev); |
|---|
| 1253 | 1296 | pm_runtime_disable(&pdev->dev); |
|---|