.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* Realtek USB SD/MMC Card Interface driver |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms of the GNU General Public License version 2 |
---|
7 | | - * as published by the Free Software Foundation. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, but |
---|
10 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | | - * General Public License for more details. |
---|
13 | | - * |
---|
14 | | - * You should have received a copy of the GNU General Public License along |
---|
15 | | - * with this program; if not, see <http://www.gnu.org/licenses/>. |
---|
16 | 5 | * |
---|
17 | 6 | * Author: |
---|
18 | 7 | * Roger Tseng <rogerable@realtek.com> |
---|
.. | .. |
---|
28 | 17 | #include <linux/mmc/sd.h> |
---|
29 | 18 | #include <linux/mmc/card.h> |
---|
30 | 19 | #include <linux/scatterlist.h> |
---|
| 20 | +#include <linux/pm.h> |
---|
31 | 21 | #include <linux/pm_runtime.h> |
---|
32 | 22 | |
---|
33 | 23 | #include <linux/rtsx_usb.h> |
---|
.. | .. |
---|
589 | 579 | static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) |
---|
590 | 580 | { |
---|
591 | 581 | struct rtsx_ucr *ucr = host->ucr; |
---|
592 | | - int err; |
---|
593 | 582 | |
---|
594 | 583 | dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n", |
---|
595 | 584 | __func__, tx ? "TX" : "RX", sample_point); |
---|
.. | .. |
---|
611 | 600 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); |
---|
612 | 601 | rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0); |
---|
613 | 602 | |
---|
614 | | - err = rtsx_usb_send_cmd(ucr, MODE_C, 100); |
---|
615 | | - if (err) |
---|
616 | | - return err; |
---|
617 | | - |
---|
618 | | - return 0; |
---|
| 603 | + return rtsx_usb_send_cmd(ucr, MODE_C, 100); |
---|
619 | 604 | } |
---|
620 | 605 | |
---|
621 | 606 | static inline u32 get_phase_point(u32 phase_map, unsigned int idx) |
---|
.. | .. |
---|
664 | 649 | |
---|
665 | 650 | static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host) |
---|
666 | 651 | { |
---|
667 | | - int err, i; |
---|
| 652 | + int i; |
---|
668 | 653 | u8 val = 0; |
---|
669 | 654 | |
---|
670 | 655 | for (i = 0; i < 100; i++) { |
---|
671 | | - err = rtsx_usb_ep0_read_register(host->ucr, |
---|
672 | | - SD_DATA_STATE, &val); |
---|
| 656 | + rtsx_usb_ep0_read_register(host->ucr, SD_DATA_STATE, &val); |
---|
673 | 657 | if (val & SD_DATA_IDLE) |
---|
674 | 658 | return; |
---|
675 | 659 | |
---|
.. | .. |
---|
1042 | 1026 | |
---|
1043 | 1027 | if (power_mode == MMC_POWER_OFF) { |
---|
1044 | 1028 | err = sd_power_off(host); |
---|
1045 | | - pm_runtime_put(sdmmc_dev(host)); |
---|
| 1029 | + pm_runtime_put_noidle(sdmmc_dev(host)); |
---|
1046 | 1030 | } else { |
---|
1047 | | - pm_runtime_get_sync(sdmmc_dev(host)); |
---|
| 1031 | + pm_runtime_get_noresume(sdmmc_dev(host)); |
---|
1048 | 1032 | err = sd_power_on(host); |
---|
1049 | 1033 | } |
---|
1050 | 1034 | |
---|
.. | .. |
---|
1297 | 1281 | container_of(work, struct rtsx_usb_sdmmc, led_work); |
---|
1298 | 1282 | struct rtsx_ucr *ucr = host->ucr; |
---|
1299 | 1283 | |
---|
1300 | | - pm_runtime_get_sync(sdmmc_dev(host)); |
---|
| 1284 | + pm_runtime_get_noresume(sdmmc_dev(host)); |
---|
1301 | 1285 | mutex_lock(&ucr->dev_mutex); |
---|
| 1286 | + |
---|
| 1287 | + if (host->power_mode == MMC_POWER_OFF) |
---|
| 1288 | + goto out; |
---|
1302 | 1289 | |
---|
1303 | 1290 | if (host->led.brightness == LED_OFF) |
---|
1304 | 1291 | rtsx_usb_turn_off_led(ucr); |
---|
1305 | 1292 | else |
---|
1306 | 1293 | rtsx_usb_turn_on_led(ucr); |
---|
1307 | 1294 | |
---|
| 1295 | +out: |
---|
1308 | 1296 | mutex_unlock(&ucr->dev_mutex); |
---|
1309 | | - pm_runtime_put(sdmmc_dev(host)); |
---|
| 1297 | + pm_runtime_put_sync_suspend(sdmmc_dev(host)); |
---|
1310 | 1298 | } |
---|
1311 | 1299 | #endif |
---|
1312 | 1300 | |
---|
.. | .. |
---|
1320 | 1308 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | |
---|
1321 | 1309 | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | |
---|
1322 | 1310 | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | |
---|
1323 | | - MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE; |
---|
| 1311 | + MMC_CAP_SYNC_RUNTIME_PM; |
---|
1324 | 1312 | mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE | |
---|
1325 | 1313 | MMC_CAP2_NO_SDIO; |
---|
1326 | 1314 | |
---|
.. | .. |
---|
1344 | 1332 | #ifdef RTSX_USB_USE_LEDS_CLASS |
---|
1345 | 1333 | int err; |
---|
1346 | 1334 | #endif |
---|
| 1335 | + int ret; |
---|
1347 | 1336 | |
---|
1348 | 1337 | ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); |
---|
1349 | 1338 | if (!ucr) |
---|
.. | .. |
---|
1363 | 1352 | |
---|
1364 | 1353 | mutex_init(&host->host_mutex); |
---|
1365 | 1354 | rtsx_usb_init_host(host); |
---|
1366 | | - pm_runtime_use_autosuspend(&pdev->dev); |
---|
1367 | | - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); |
---|
1368 | 1355 | pm_runtime_enable(&pdev->dev); |
---|
1369 | 1356 | |
---|
1370 | 1357 | #ifdef RTSX_USB_USE_LEDS_CLASS |
---|
.. | .. |
---|
1382 | 1369 | INIT_WORK(&host->led_work, rtsx_usb_update_led); |
---|
1383 | 1370 | |
---|
1384 | 1371 | #endif |
---|
1385 | | - mmc_add_host(mmc); |
---|
| 1372 | + ret = mmc_add_host(mmc); |
---|
| 1373 | + if (ret) { |
---|
| 1374 | +#ifdef RTSX_USB_USE_LEDS_CLASS |
---|
| 1375 | + led_classdev_unregister(&host->led); |
---|
| 1376 | +#endif |
---|
| 1377 | + mmc_free_host(mmc); |
---|
| 1378 | + pm_runtime_disable(&pdev->dev); |
---|
| 1379 | + return ret; |
---|
| 1380 | + } |
---|
1386 | 1381 | |
---|
1387 | 1382 | return 0; |
---|
1388 | 1383 | } |
---|
.. | .. |
---|
1419 | 1414 | |
---|
1420 | 1415 | mmc_free_host(mmc); |
---|
1421 | 1416 | pm_runtime_disable(&pdev->dev); |
---|
1422 | | - pm_runtime_dont_use_autosuspend(&pdev->dev); |
---|
1423 | 1417 | platform_set_drvdata(pdev, NULL); |
---|
1424 | 1418 | |
---|
1425 | 1419 | dev_dbg(&(pdev->dev), |
---|
.. | .. |
---|
1427 | 1421 | |
---|
1428 | 1422 | return 0; |
---|
1429 | 1423 | } |
---|
| 1424 | + |
---|
| 1425 | +#ifdef CONFIG_PM |
---|
| 1426 | +static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev) |
---|
| 1427 | +{ |
---|
| 1428 | + struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev); |
---|
| 1429 | + |
---|
| 1430 | + host->mmc->caps &= ~MMC_CAP_NEEDS_POLL; |
---|
| 1431 | + return 0; |
---|
| 1432 | +} |
---|
| 1433 | + |
---|
| 1434 | +static int rtsx_usb_sdmmc_runtime_resume(struct device *dev) |
---|
| 1435 | +{ |
---|
| 1436 | + struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev); |
---|
| 1437 | + |
---|
| 1438 | + host->mmc->caps |= MMC_CAP_NEEDS_POLL; |
---|
| 1439 | + if (sdmmc_get_cd(host->mmc) == 1) |
---|
| 1440 | + mmc_detect_change(host->mmc, 0); |
---|
| 1441 | + return 0; |
---|
| 1442 | +} |
---|
| 1443 | +#endif |
---|
| 1444 | + |
---|
| 1445 | +static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = { |
---|
| 1446 | + SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend, |
---|
| 1447 | + rtsx_usb_sdmmc_runtime_resume, NULL) |
---|
| 1448 | +}; |
---|
1430 | 1449 | |
---|
1431 | 1450 | static const struct platform_device_id rtsx_usb_sdmmc_ids[] = { |
---|
1432 | 1451 | { |
---|
.. | .. |
---|
1443 | 1462 | .id_table = rtsx_usb_sdmmc_ids, |
---|
1444 | 1463 | .driver = { |
---|
1445 | 1464 | .name = "rtsx_usb_sdmmc", |
---|
| 1465 | + .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
---|
| 1466 | + .pm = &rtsx_usb_sdmmc_dev_pm_ops, |
---|
1446 | 1467 | }, |
---|
1447 | 1468 | }; |
---|
1448 | 1469 | module_platform_driver(rtsx_usb_sdmmc_driver); |
---|