18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/mmc/sdio.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2006-2007 Pierre Ossman 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/mmc/host.h> 128c2ecf20Sopenharmony_ci#include <linux/mmc/card.h> 138c2ecf20Sopenharmony_ci#include <linux/mmc/mmc.h> 148c2ecf20Sopenharmony_ci#include <linux/mmc/sdio.h> 158c2ecf20Sopenharmony_ci#include <linux/mmc/sdio_func.h> 168c2ecf20Sopenharmony_ci#include <linux/mmc/sdio_ids.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "core.h" 198c2ecf20Sopenharmony_ci#include "card.h" 208c2ecf20Sopenharmony_ci#include "host.h" 218c2ecf20Sopenharmony_ci#include "bus.h" 228c2ecf20Sopenharmony_ci#include "quirks.h" 238c2ecf20Sopenharmony_ci#include "sd.h" 248c2ecf20Sopenharmony_ci#include "sdio_bus.h" 258c2ecf20Sopenharmony_ci#include "mmc_ops.h" 268c2ecf20Sopenharmony_ci#include "sd_ops.h" 278c2ecf20Sopenharmony_ci#include "sdio_ops.h" 288c2ecf20Sopenharmony_ci#include "sdio_cis.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciMMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); 318c2ecf20Sopenharmony_ciMMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); 328c2ecf20Sopenharmony_ciMMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev); 338c2ecf20Sopenharmony_ciMMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); 348c2ecf20Sopenharmony_ciMMC_DEV_ATTR(rca, "0x%04x\n", card->rca); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define sdio_info_attr(num) \ 378c2ecf20Sopenharmony_cistatic ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 388c2ecf20Sopenharmony_ci{ \ 398c2ecf20Sopenharmony_ci struct mmc_card *card = mmc_dev_to_card(dev); \ 408c2ecf20Sopenharmony_ci \ 418c2ecf20Sopenharmony_ci if (num > card->num_info) \ 428c2ecf20Sopenharmony_ci return -ENODATA; \ 438c2ecf20Sopenharmony_ci if (!card->info[num-1][0]) \ 448c2ecf20Sopenharmony_ci return 0; \ 458c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", card->info[num-1]); \ 468c2ecf20Sopenharmony_ci} \ 478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(info##num) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cisdio_info_attr(1); 508c2ecf20Sopenharmony_cisdio_info_attr(2); 518c2ecf20Sopenharmony_cisdio_info_attr(3); 528c2ecf20Sopenharmony_cisdio_info_attr(4); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic struct attribute *sdio_std_attrs[] = { 558c2ecf20Sopenharmony_ci &dev_attr_vendor.attr, 568c2ecf20Sopenharmony_ci &dev_attr_device.attr, 578c2ecf20Sopenharmony_ci &dev_attr_revision.attr, 588c2ecf20Sopenharmony_ci &dev_attr_info1.attr, 598c2ecf20Sopenharmony_ci &dev_attr_info2.attr, 608c2ecf20Sopenharmony_ci &dev_attr_info3.attr, 618c2ecf20Sopenharmony_ci &dev_attr_info4.attr, 628c2ecf20Sopenharmony_ci &dev_attr_ocr.attr, 638c2ecf20Sopenharmony_ci &dev_attr_rca.attr, 648c2ecf20Sopenharmony_ci NULL, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(sdio_std); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct device_type sdio_type = { 698c2ecf20Sopenharmony_ci .groups = sdio_std_groups, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int sdio_read_fbr(struct sdio_func *func) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci unsigned char data; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (mmc_card_nonstd_func_interface(func->card)) { 788c2ecf20Sopenharmony_ci func->class = SDIO_CLASS_NONE; 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(func->card, 0, 0, 838c2ecf20Sopenharmony_ci SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); 848c2ecf20Sopenharmony_ci if (ret) 858c2ecf20Sopenharmony_ci goto out; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci data &= 0x0f; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (data == 0x0f) { 908c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(func->card, 0, 0, 918c2ecf20Sopenharmony_ci SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); 928c2ecf20Sopenharmony_ci if (ret) 938c2ecf20Sopenharmony_ci goto out; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci func->class = data; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciout: 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int sdio_init_func(struct mmc_card *card, unsigned int fn) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int ret; 1058c2ecf20Sopenharmony_ci struct sdio_func *func; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (WARN_ON(fn > SDIO_MAX_FUNCS)) 1088c2ecf20Sopenharmony_ci return -EINVAL; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci func = sdio_alloc_func(card); 1118c2ecf20Sopenharmony_ci if (IS_ERR(func)) 1128c2ecf20Sopenharmony_ci return PTR_ERR(func); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci func->num = fn; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!(card->quirks & MMC_QUIRK_NONSTD_SDIO)) { 1178c2ecf20Sopenharmony_ci ret = sdio_read_fbr(func); 1188c2ecf20Sopenharmony_ci if (ret) 1198c2ecf20Sopenharmony_ci goto fail; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ret = sdio_read_func_cis(func); 1228c2ecf20Sopenharmony_ci if (ret) 1238c2ecf20Sopenharmony_ci goto fail; 1248c2ecf20Sopenharmony_ci } else { 1258c2ecf20Sopenharmony_ci func->vendor = func->card->cis.vendor; 1268c2ecf20Sopenharmony_ci func->device = func->card->cis.device; 1278c2ecf20Sopenharmony_ci func->max_blksize = func->card->cis.blksize; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci card->sdio_func[fn - 1] = func; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cifail: 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * It is okay to remove the function here even though we hold 1378c2ecf20Sopenharmony_ci * the host lock as we haven't registered the device yet. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci sdio_remove_func(func); 1408c2ecf20Sopenharmony_ci return ret; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int sdio_read_cccr(struct mmc_card *card, u32 ocr) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci int ret; 1468c2ecf20Sopenharmony_ci int cccr_vsn; 1478c2ecf20Sopenharmony_ci int uhs = ocr & R4_18V_PRESENT; 1488c2ecf20Sopenharmony_ci unsigned char data; 1498c2ecf20Sopenharmony_ci unsigned char speed; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); 1528c2ecf20Sopenharmony_ci if (ret) 1538c2ecf20Sopenharmony_ci goto out; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci cccr_vsn = data & 0x0f; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (cccr_vsn > SDIO_CCCR_REV_3_00) { 1588c2ecf20Sopenharmony_ci pr_err("%s: unrecognised CCCR structure version %d\n", 1598c2ecf20Sopenharmony_ci mmc_hostname(card->host), cccr_vsn); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci card->cccr.sdio_vsn = (data & 0xf0) >> 4; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); 1668c2ecf20Sopenharmony_ci if (ret) 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (data & SDIO_CCCR_CAP_SMB) 1708c2ecf20Sopenharmony_ci card->cccr.multi_block = 1; 1718c2ecf20Sopenharmony_ci if (data & SDIO_CCCR_CAP_LSC) 1728c2ecf20Sopenharmony_ci card->cccr.low_speed = 1; 1738c2ecf20Sopenharmony_ci if (data & SDIO_CCCR_CAP_4BLS) 1748c2ecf20Sopenharmony_ci card->cccr.wide_bus = 1; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (cccr_vsn >= SDIO_CCCR_REV_1_10) { 1778c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); 1788c2ecf20Sopenharmony_ci if (ret) 1798c2ecf20Sopenharmony_ci goto out; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (data & SDIO_POWER_SMPC) 1828c2ecf20Sopenharmony_ci card->cccr.high_power = 1; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (cccr_vsn >= SDIO_CCCR_REV_1_20) { 1868c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci goto out; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci card->scr.sda_spec3 = 0; 1918c2ecf20Sopenharmony_ci card->sw_caps.sd3_bus_mode = 0; 1928c2ecf20Sopenharmony_ci card->sw_caps.sd3_drv_type = 0; 1938c2ecf20Sopenharmony_ci if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) { 1948c2ecf20Sopenharmony_ci card->scr.sda_spec3 = 1; 1958c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, 1968c2ecf20Sopenharmony_ci SDIO_CCCR_UHS, 0, &data); 1978c2ecf20Sopenharmony_ci if (ret) 1988c2ecf20Sopenharmony_ci goto out; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (mmc_host_uhs(card->host)) { 2018c2ecf20Sopenharmony_ci if (data & SDIO_UHS_DDR50) 2028c2ecf20Sopenharmony_ci card->sw_caps.sd3_bus_mode 2038c2ecf20Sopenharmony_ci |= SD_MODE_UHS_DDR50 | SD_MODE_UHS_SDR50 2048c2ecf20Sopenharmony_ci | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (data & SDIO_UHS_SDR50) 2078c2ecf20Sopenharmony_ci card->sw_caps.sd3_bus_mode 2088c2ecf20Sopenharmony_ci |= SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR25 2098c2ecf20Sopenharmony_ci | SD_MODE_UHS_SDR12; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (data & SDIO_UHS_SDR104) 2128c2ecf20Sopenharmony_ci card->sw_caps.sd3_bus_mode 2138c2ecf20Sopenharmony_ci |= SD_MODE_UHS_SDR104 | SD_MODE_UHS_SDR50 2148c2ecf20Sopenharmony_ci | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, 2188c2ecf20Sopenharmony_ci SDIO_CCCR_DRIVE_STRENGTH, 0, &data); 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci goto out; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (data & SDIO_DRIVE_SDTA) 2238c2ecf20Sopenharmony_ci card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A; 2248c2ecf20Sopenharmony_ci if (data & SDIO_DRIVE_SDTC) 2258c2ecf20Sopenharmony_ci card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C; 2268c2ecf20Sopenharmony_ci if (data & SDIO_DRIVE_SDTD) 2278c2ecf20Sopenharmony_ci card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* if no uhs mode ensure we check for high speed */ 2318c2ecf20Sopenharmony_ci if (!card->sw_caps.sd3_bus_mode) { 2328c2ecf20Sopenharmony_ci if (speed & SDIO_SPEED_SHS) { 2338c2ecf20Sopenharmony_ci card->cccr.high_speed = 1; 2348c2ecf20Sopenharmony_ci card->sw_caps.hs_max_dtr = 50000000; 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci card->cccr.high_speed = 0; 2378c2ecf20Sopenharmony_ci card->sw_caps.hs_max_dtr = 25000000; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciout: 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int sdio_enable_wide(struct mmc_card *card) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int ret; 2498c2ecf20Sopenharmony_ci u8 ctrl; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (card->cccr.low_speed && !card->cccr.wide_bus) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); 2588c2ecf20Sopenharmony_ci if (ret) 2598c2ecf20Sopenharmony_ci return ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED) 2628c2ecf20Sopenharmony_ci pr_warn("%s: SDIO_CCCR_IF is invalid: 0x%02x\n", 2638c2ecf20Sopenharmony_ci mmc_hostname(card->host), ctrl); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* set as 4-bit bus width */ 2668c2ecf20Sopenharmony_ci ctrl &= ~SDIO_BUS_WIDTH_MASK; 2678c2ecf20Sopenharmony_ci ctrl |= SDIO_BUS_WIDTH_4BIT; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); 2708c2ecf20Sopenharmony_ci if (ret) 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 1; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* 2778c2ecf20Sopenharmony_ci * If desired, disconnect the pull-up resistor on CD/DAT[3] (pin 1) 2788c2ecf20Sopenharmony_ci * of the card. This may be required on certain setups of boards, 2798c2ecf20Sopenharmony_ci * controllers and embedded sdio device which do not need the card's 2808c2ecf20Sopenharmony_ci * pull-up. As a result, card detection is disabled and power is saved. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_cistatic int sdio_disable_cd(struct mmc_card *card) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int ret; 2858c2ecf20Sopenharmony_ci u8 ctrl; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!mmc_card_disable_cd(card)) 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); 2918c2ecf20Sopenharmony_ci if (ret) 2928c2ecf20Sopenharmony_ci return ret; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci ctrl |= SDIO_BUS_CD_DISABLE; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * Devices that remain active during a system suspend are 3018c2ecf20Sopenharmony_ci * put back into 1-bit mode. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_cistatic int sdio_disable_wide(struct mmc_card *card) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci int ret; 3068c2ecf20Sopenharmony_ci u8 ctrl; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (card->cccr.low_speed && !card->cccr.wide_bus) 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); 3158c2ecf20Sopenharmony_ci if (ret) 3168c2ecf20Sopenharmony_ci return ret; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (!(ctrl & SDIO_BUS_WIDTH_4BIT)) 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ctrl &= ~SDIO_BUS_WIDTH_4BIT; 3228c2ecf20Sopenharmony_ci ctrl |= SDIO_BUS_ASYNC_INT; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); 3258c2ecf20Sopenharmony_ci if (ret) 3268c2ecf20Sopenharmony_ci return ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci mmc_set_bus_width(card->host, MMC_BUS_WIDTH_1); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int sdio_disable_4bit_bus(struct mmc_card *card) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci int err; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (card->type == MMC_TYPE_SDIO) 3388c2ecf20Sopenharmony_ci goto out; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); 3478c2ecf20Sopenharmony_ci if (err) 3488c2ecf20Sopenharmony_ci return err; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciout: 3518c2ecf20Sopenharmony_ci return sdio_disable_wide(card); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int sdio_enable_4bit_bus(struct mmc_card *card) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int err; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci err = sdio_enable_wide(card); 3608c2ecf20Sopenharmony_ci if (err <= 0) 3618c2ecf20Sopenharmony_ci return err; 3628c2ecf20Sopenharmony_ci if (card->type == MMC_TYPE_SDIO) 3638c2ecf20Sopenharmony_ci goto out; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) { 3668c2ecf20Sopenharmony_ci err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); 3678c2ecf20Sopenharmony_ci if (err) { 3688c2ecf20Sopenharmony_ci sdio_disable_wide(card); 3698c2ecf20Sopenharmony_ci return err; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ciout: 3738c2ecf20Sopenharmony_ci mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * Test if the card supports high-speed mode and, if so, switch to it. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistatic int mmc_sdio_switch_hs(struct mmc_card *card, int enable) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci u8 speed; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!card->cccr.high_speed) 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); 3948c2ecf20Sopenharmony_ci if (ret) 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (enable) 3988c2ecf20Sopenharmony_ci speed |= SDIO_SPEED_EHS; 3998c2ecf20Sopenharmony_ci else 4008c2ecf20Sopenharmony_ci speed &= ~SDIO_SPEED_EHS; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); 4038c2ecf20Sopenharmony_ci if (ret) 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 1; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_cistatic int sdio_enable_hs(struct mmc_card *card) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci int ret; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ret = mmc_sdio_switch_hs(card, true); 4178c2ecf20Sopenharmony_ci if (ret <= 0 || card->type == MMC_TYPE_SDIO) 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ret = mmc_sd_switch_hs(card); 4218c2ecf20Sopenharmony_ci if (ret <= 0) 4228c2ecf20Sopenharmony_ci mmc_sdio_switch_hs(card, false); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic unsigned mmc_sdio_get_max_clock(struct mmc_card *card) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci unsigned max_dtr; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (mmc_card_hs(card)) { 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * The SDIO specification doesn't mention how 4348c2ecf20Sopenharmony_ci * the CIS transfer speed register relates to 4358c2ecf20Sopenharmony_ci * high-speed, but it seems that 50 MHz is 4368c2ecf20Sopenharmony_ci * mandatory. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci max_dtr = 50000000; 4398c2ecf20Sopenharmony_ci } else { 4408c2ecf20Sopenharmony_ci max_dtr = card->cis.max_dtr; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (card->type == MMC_TYPE_SD_COMBO) 4448c2ecf20Sopenharmony_ci max_dtr = min(max_dtr, mmc_sd_get_max_clock(card)); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return max_dtr; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic unsigned char host_drive_to_sdio_drive(int host_strength) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci switch (host_strength) { 4528c2ecf20Sopenharmony_ci case MMC_SET_DRIVER_TYPE_A: 4538c2ecf20Sopenharmony_ci return SDIO_DTSx_SET_TYPE_A; 4548c2ecf20Sopenharmony_ci case MMC_SET_DRIVER_TYPE_B: 4558c2ecf20Sopenharmony_ci return SDIO_DTSx_SET_TYPE_B; 4568c2ecf20Sopenharmony_ci case MMC_SET_DRIVER_TYPE_C: 4578c2ecf20Sopenharmony_ci return SDIO_DTSx_SET_TYPE_C; 4588c2ecf20Sopenharmony_ci case MMC_SET_DRIVER_TYPE_D: 4598c2ecf20Sopenharmony_ci return SDIO_DTSx_SET_TYPE_D; 4608c2ecf20Sopenharmony_ci default: 4618c2ecf20Sopenharmony_ci return SDIO_DTSx_SET_TYPE_B; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void sdio_select_driver_type(struct mmc_card *card) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int card_drv_type, drive_strength, drv_type; 4688c2ecf20Sopenharmony_ci unsigned char card_strength; 4698c2ecf20Sopenharmony_ci int err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci card->drive_strength = 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci card_drv_type = card->sw_caps.sd3_drv_type | SD_DRIVER_TYPE_B; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci drive_strength = mmc_select_drive_strength(card, 4768c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr, 4778c2ecf20Sopenharmony_ci card_drv_type, &drv_type); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (drive_strength) { 4808c2ecf20Sopenharmony_ci /* if error just use default for drive strength B */ 4818c2ecf20Sopenharmony_ci err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, 4828c2ecf20Sopenharmony_ci &card_strength); 4838c2ecf20Sopenharmony_ci if (err) 4848c2ecf20Sopenharmony_ci return; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); 4878c2ecf20Sopenharmony_ci card_strength |= host_drive_to_sdio_drive(drive_strength); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* if error default to drive strength B */ 4908c2ecf20Sopenharmony_ci err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, 4918c2ecf20Sopenharmony_ci card_strength, NULL); 4928c2ecf20Sopenharmony_ci if (err) 4938c2ecf20Sopenharmony_ci return; 4948c2ecf20Sopenharmony_ci card->drive_strength = drive_strength; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (drv_type) 4988c2ecf20Sopenharmony_ci mmc_set_driver_type(card->host, drv_type); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int sdio_set_bus_speed_mode(struct mmc_card *card) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci unsigned int bus_speed, timing; 5058c2ecf20Sopenharmony_ci int err; 5068c2ecf20Sopenharmony_ci unsigned char speed; 5078c2ecf20Sopenharmony_ci unsigned int max_rate; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* 5108c2ecf20Sopenharmony_ci * If the host doesn't support any of the UHS-I modes, fallback on 5118c2ecf20Sopenharmony_ci * default speed. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci if (!mmc_host_uhs(card->host)) 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_SDR12; 5178c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_SDR12; 5188c2ecf20Sopenharmony_ci if ((card->host->caps & MMC_CAP_UHS_SDR104) && 5198c2ecf20Sopenharmony_ci (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { 5208c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_SDR104; 5218c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_SDR104; 5228c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; 5238c2ecf20Sopenharmony_ci card->sd_bus_speed = UHS_SDR104_BUS_SPEED; 5248c2ecf20Sopenharmony_ci } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && 5258c2ecf20Sopenharmony_ci (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { 5268c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_DDR50; 5278c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_DDR50; 5288c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; 5298c2ecf20Sopenharmony_ci card->sd_bus_speed = UHS_DDR50_BUS_SPEED; 5308c2ecf20Sopenharmony_ci } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | 5318c2ecf20Sopenharmony_ci MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & 5328c2ecf20Sopenharmony_ci SD_MODE_UHS_SDR50)) { 5338c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_SDR50; 5348c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_SDR50; 5358c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; 5368c2ecf20Sopenharmony_ci card->sd_bus_speed = UHS_SDR50_BUS_SPEED; 5378c2ecf20Sopenharmony_ci } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | 5388c2ecf20Sopenharmony_ci MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && 5398c2ecf20Sopenharmony_ci (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { 5408c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_SDR25; 5418c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_SDR25; 5428c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; 5438c2ecf20Sopenharmony_ci card->sd_bus_speed = UHS_SDR25_BUS_SPEED; 5448c2ecf20Sopenharmony_ci } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | 5458c2ecf20Sopenharmony_ci MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | 5468c2ecf20Sopenharmony_ci MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & 5478c2ecf20Sopenharmony_ci SD_MODE_UHS_SDR12)) { 5488c2ecf20Sopenharmony_ci bus_speed = SDIO_SPEED_SDR12; 5498c2ecf20Sopenharmony_ci timing = MMC_TIMING_UHS_SDR12; 5508c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; 5518c2ecf20Sopenharmony_ci card->sd_bus_speed = UHS_SDR12_BUS_SPEED; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); 5558c2ecf20Sopenharmony_ci if (err) 5568c2ecf20Sopenharmony_ci return err; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci speed &= ~SDIO_SPEED_BSS_MASK; 5598c2ecf20Sopenharmony_ci speed |= bus_speed; 5608c2ecf20Sopenharmony_ci err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); 5618c2ecf20Sopenharmony_ci if (err) 5628c2ecf20Sopenharmony_ci return err; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci max_rate = min_not_zero(card->quirk_max_rate, 5658c2ecf20Sopenharmony_ci card->sw_caps.uhs_max_dtr); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci mmc_set_timing(card->host, timing); 5688c2ecf20Sopenharmony_ci mmc_set_clock(card->host, max_rate); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/* 5748c2ecf20Sopenharmony_ci * UHS-I specific initialization procedure 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_cistatic int mmc_sdio_init_uhs_card(struct mmc_card *card) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int err; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!card->scr.sda_spec3) 5818c2ecf20Sopenharmony_ci return 0; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Switch to wider bus */ 5848c2ecf20Sopenharmony_ci err = sdio_enable_4bit_bus(card); 5858c2ecf20Sopenharmony_ci if (err) 5868c2ecf20Sopenharmony_ci goto out; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Set the driver strength for the card */ 5898c2ecf20Sopenharmony_ci sdio_select_driver_type(card); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Set bus speed mode of the card */ 5928c2ecf20Sopenharmony_ci err = sdio_set_bus_speed_mode(card); 5938c2ecf20Sopenharmony_ci if (err) 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and 5988c2ecf20Sopenharmony_ci * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci if (!mmc_host_is_spi(card->host) && 6018c2ecf20Sopenharmony_ci ((card->host->ios.timing == MMC_TIMING_UHS_SDR50) || 6028c2ecf20Sopenharmony_ci (card->host->ios.timing == MMC_TIMING_UHS_SDR104))) 6038c2ecf20Sopenharmony_ci err = mmc_execute_tuning(card); 6048c2ecf20Sopenharmony_ciout: 6058c2ecf20Sopenharmony_ci return err; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int mmc_sdio_pre_init(struct mmc_host *host, u32 ocr, 6098c2ecf20Sopenharmony_ci struct mmc_card *card) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci if (card) 6128c2ecf20Sopenharmony_ci mmc_remove_card(card); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * Reset the card by performing the same steps that are taken by 6168c2ecf20Sopenharmony_ci * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * sdio_reset() is technically not needed. Having just powered up the 6198c2ecf20Sopenharmony_ci * hardware, it should already be in reset state. However, some 6208c2ecf20Sopenharmony_ci * platforms (such as SD8686 on OLPC) do not instantly cut power, 6218c2ecf20Sopenharmony_ci * meaning that a reset is required when restoring power soon after 6228c2ecf20Sopenharmony_ci * powering off. It is harmless in other cases. 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, 6258c2ecf20Sopenharmony_ci * is not necessary for non-removable cards. However, it is required 6268c2ecf20Sopenharmony_ci * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and 6278c2ecf20Sopenharmony_ci * harmless in other situations. 6288c2ecf20Sopenharmony_ci * 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci sdio_reset(host); 6328c2ecf20Sopenharmony_ci mmc_go_idle(host); 6338c2ecf20Sopenharmony_ci mmc_send_if_cond(host, ocr); 6348c2ecf20Sopenharmony_ci return mmc_send_io_op_cond(host, 0, NULL); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/* 6388c2ecf20Sopenharmony_ci * Handle the detection and initialisation of a card. 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * In the case of a resume, "oldcard" will contain the card 6418c2ecf20Sopenharmony_ci * we're trying to reinitialise. 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_cistatic int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, 6448c2ecf20Sopenharmony_ci struct mmc_card *oldcard) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct mmc_card *card; 6478c2ecf20Sopenharmony_ci int err; 6488c2ecf20Sopenharmony_ci int retries = 10; 6498c2ecf20Sopenharmony_ci u32 rocr = 0; 6508c2ecf20Sopenharmony_ci u32 ocr_card = ocr; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci WARN_ON(!host->claimed); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* to query card if 1.8V signalling is supported */ 6558c2ecf20Sopenharmony_ci if (mmc_host_uhs(host)) 6568c2ecf20Sopenharmony_ci ocr |= R4_18V_PRESENT; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_citry_again: 6598c2ecf20Sopenharmony_ci if (!retries) { 6608c2ecf20Sopenharmony_ci pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host)); 6618c2ecf20Sopenharmony_ci ocr &= ~R4_18V_PRESENT; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * Inform the card of the voltage 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_ci err = mmc_send_io_op_cond(host, ocr, &rocr); 6688c2ecf20Sopenharmony_ci if (err) 6698c2ecf20Sopenharmony_ci return err; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * For SPI, enable CRC as appropriate. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci if (mmc_host_is_spi(host)) { 6758c2ecf20Sopenharmony_ci err = mmc_spi_set_crc(host, use_spi_crc); 6768c2ecf20Sopenharmony_ci if (err) 6778c2ecf20Sopenharmony_ci return err; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* 6818c2ecf20Sopenharmony_ci * Allocate card structure. 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci card = mmc_alloc_card(host, &sdio_type); 6848c2ecf20Sopenharmony_ci if (IS_ERR(card)) 6858c2ecf20Sopenharmony_ci return PTR_ERR(card); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if ((rocr & R4_MEMORY_PRESENT) && 6888c2ecf20Sopenharmony_ci mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) { 6898c2ecf20Sopenharmony_ci card->type = MMC_TYPE_SD_COMBO; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || 6928c2ecf20Sopenharmony_ci memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { 6938c2ecf20Sopenharmony_ci err = -ENOENT; 6948c2ecf20Sopenharmony_ci goto mismatch; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci } else { 6978c2ecf20Sopenharmony_ci card->type = MMC_TYPE_SDIO; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (oldcard && oldcard->type != MMC_TYPE_SDIO) { 7008c2ecf20Sopenharmony_ci err = -ENOENT; 7018c2ecf20Sopenharmony_ci goto mismatch; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * Call the optional HC's init_card function to handle quirks. 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_ci if (host->ops->init_card) 7098c2ecf20Sopenharmony_ci host->ops->init_card(host, card); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci card->ocr = ocr_card; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * If the host and card support UHS-I mode request the card 7158c2ecf20Sopenharmony_ci * to switch to 1.8V signaling level. No 1.8v signalling if 7168c2ecf20Sopenharmony_ci * UHS mode is not enabled to maintain compatibility and some 7178c2ecf20Sopenharmony_ci * systems that claim 1.8v signalling in fact do not support 7188c2ecf20Sopenharmony_ci * it. Per SDIO spec v3, section 3.1.2, if the voltage is already 7198c2ecf20Sopenharmony_ci * 1.8v, the card sets S18A to 0 in the R4 response. So it will 7208c2ecf20Sopenharmony_ci * fails to check rocr & R4_18V_PRESENT, but we still need to 7218c2ecf20Sopenharmony_ci * try to init uhs card. sdio_read_cccr will take over this task 7228c2ecf20Sopenharmony_ci * to make sure which speed mode should work. 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_ci if (rocr & ocr & R4_18V_PRESENT) { 7258c2ecf20Sopenharmony_ci err = mmc_set_uhs_voltage(host, ocr_card); 7268c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 7278c2ecf20Sopenharmony_ci mmc_sdio_pre_init(host, ocr_card, card); 7288c2ecf20Sopenharmony_ci retries--; 7298c2ecf20Sopenharmony_ci goto try_again; 7308c2ecf20Sopenharmony_ci } else if (err) { 7318c2ecf20Sopenharmony_ci ocr &= ~R4_18V_PRESENT; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * For native busses: set card RCA and quit open drain mode. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci if (!mmc_host_is_spi(host)) { 7398c2ecf20Sopenharmony_ci err = mmc_send_relative_addr(host, &card->rca); 7408c2ecf20Sopenharmony_ci if (err) 7418c2ecf20Sopenharmony_ci goto remove; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* 7448c2ecf20Sopenharmony_ci * Update oldcard with the new RCA received from the SDIO 7458c2ecf20Sopenharmony_ci * device -- we're doing this so that it's updated in the 7468c2ecf20Sopenharmony_ci * "card" struct when oldcard overwrites that later. 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ci if (oldcard) 7498c2ecf20Sopenharmony_ci oldcard->rca = card->rca; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* 7538c2ecf20Sopenharmony_ci * Read CSD, before selecting the card 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci if (!oldcard && card->type == MMC_TYPE_SD_COMBO) { 7568c2ecf20Sopenharmony_ci err = mmc_sd_get_csd(host, card); 7578c2ecf20Sopenharmony_ci if (err) 7588c2ecf20Sopenharmony_ci goto remove; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci mmc_decode_cid(card); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* 7648c2ecf20Sopenharmony_ci * Select card, as all following commands rely on that. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci if (!mmc_host_is_spi(host)) { 7678c2ecf20Sopenharmony_ci err = mmc_select_card(card); 7688c2ecf20Sopenharmony_ci if (err) 7698c2ecf20Sopenharmony_ci goto remove; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (card->quirks & MMC_QUIRK_NONSTD_SDIO) { 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * This is non-standard SDIO device, meaning it doesn't 7758c2ecf20Sopenharmony_ci * have any CIA (Common I/O area) registers present. 7768c2ecf20Sopenharmony_ci * It's host's responsibility to fill cccr and cis 7778c2ecf20Sopenharmony_ci * structures in init_card(). 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci mmc_set_clock(host, card->cis.max_dtr); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (card->cccr.high_speed) { 7828c2ecf20Sopenharmony_ci mmc_set_timing(card->host, MMC_TIMING_SD_HS); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (oldcard) 7868c2ecf20Sopenharmony_ci mmc_remove_card(card); 7878c2ecf20Sopenharmony_ci else 7888c2ecf20Sopenharmony_ci host->card = card; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * Read the common registers. Note that we should try to 7958c2ecf20Sopenharmony_ci * validate whether UHS would work or not. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci err = sdio_read_cccr(card, ocr); 7988c2ecf20Sopenharmony_ci if (err) { 7998c2ecf20Sopenharmony_ci mmc_sdio_pre_init(host, ocr_card, card); 8008c2ecf20Sopenharmony_ci if (ocr & R4_18V_PRESENT) { 8018c2ecf20Sopenharmony_ci /* Retry init sequence, but without R4_18V_PRESENT. */ 8028c2ecf20Sopenharmony_ci retries = 0; 8038c2ecf20Sopenharmony_ci goto try_again; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci return err; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* 8098c2ecf20Sopenharmony_ci * Read the common CIS tuples. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_ci err = sdio_read_common_cis(card); 8128c2ecf20Sopenharmony_ci if (err) 8138c2ecf20Sopenharmony_ci goto remove; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (oldcard) { 8168c2ecf20Sopenharmony_ci if (card->cis.vendor == oldcard->cis.vendor && 8178c2ecf20Sopenharmony_ci card->cis.device == oldcard->cis.device) { 8188c2ecf20Sopenharmony_ci mmc_remove_card(card); 8198c2ecf20Sopenharmony_ci card = oldcard; 8208c2ecf20Sopenharmony_ci } else { 8218c2ecf20Sopenharmony_ci err = -ENOENT; 8228c2ecf20Sopenharmony_ci goto mismatch; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci mmc_fixup_device(card, sdio_fixup_methods); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (card->type == MMC_TYPE_SD_COMBO) { 8298c2ecf20Sopenharmony_ci err = mmc_sd_setup_card(host, card, oldcard != NULL); 8308c2ecf20Sopenharmony_ci /* handle as SDIO-only card if memory init failed */ 8318c2ecf20Sopenharmony_ci if (err) { 8328c2ecf20Sopenharmony_ci mmc_go_idle(host); 8338c2ecf20Sopenharmony_ci if (mmc_host_is_spi(host)) 8348c2ecf20Sopenharmony_ci /* should not fail, as it worked previously */ 8358c2ecf20Sopenharmony_ci mmc_spi_set_crc(host, use_spi_crc); 8368c2ecf20Sopenharmony_ci card->type = MMC_TYPE_SDIO; 8378c2ecf20Sopenharmony_ci } else 8388c2ecf20Sopenharmony_ci card->dev.type = &sd_type; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * If needed, disconnect card detection pull-up resistor. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci err = sdio_disable_cd(card); 8458c2ecf20Sopenharmony_ci if (err) 8468c2ecf20Sopenharmony_ci goto remove; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Initialization sequence for UHS-I cards */ 8498c2ecf20Sopenharmony_ci /* Only if card supports 1.8v and UHS signaling */ 8508c2ecf20Sopenharmony_ci if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) { 8518c2ecf20Sopenharmony_ci err = mmc_sdio_init_uhs_card(card); 8528c2ecf20Sopenharmony_ci if (err) 8538c2ecf20Sopenharmony_ci goto remove; 8548c2ecf20Sopenharmony_ci } else { 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * Switch to high-speed (if supported). 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_ci err = sdio_enable_hs(card); 8598c2ecf20Sopenharmony_ci if (err > 0) 8608c2ecf20Sopenharmony_ci mmc_set_timing(card->host, MMC_TIMING_SD_HS); 8618c2ecf20Sopenharmony_ci else if (err) 8628c2ecf20Sopenharmony_ci goto remove; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* 8658c2ecf20Sopenharmony_ci * Change to the card's maximum speed. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci mmc_set_clock(host, mmc_sdio_get_max_clock(card)); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* 8708c2ecf20Sopenharmony_ci * Switch to wider bus (if supported). 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci err = sdio_enable_4bit_bus(card); 8738c2ecf20Sopenharmony_ci if (err) 8748c2ecf20Sopenharmony_ci goto remove; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (host->caps2 & MMC_CAP2_AVOID_3_3V && 8788c2ecf20Sopenharmony_ci host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 8798c2ecf20Sopenharmony_ci pr_err("%s: Host failed to negotiate down from 3.3V\n", 8808c2ecf20Sopenharmony_ci mmc_hostname(host)); 8818c2ecf20Sopenharmony_ci err = -EINVAL; 8828c2ecf20Sopenharmony_ci goto remove; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci host->card = card; 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cimismatch: 8898c2ecf20Sopenharmony_ci pr_debug("%s: Perhaps the card was replaced\n", mmc_hostname(host)); 8908c2ecf20Sopenharmony_ciremove: 8918c2ecf20Sopenharmony_ci if (oldcard != card) 8928c2ecf20Sopenharmony_ci mmc_remove_card(card); 8938c2ecf20Sopenharmony_ci return err; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic int mmc_sdio_reinit_card(struct mmc_host *host) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci int ret; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci ret = mmc_sdio_pre_init(host, host->card->ocr, NULL); 9018c2ecf20Sopenharmony_ci if (ret) 9028c2ecf20Sopenharmony_ci return ret; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return mmc_sdio_init_card(host, host->card->ocr, host->card); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/* 9088c2ecf20Sopenharmony_ci * Host is being removed. Free up the current card. 9098c2ecf20Sopenharmony_ci */ 9108c2ecf20Sopenharmony_cistatic void mmc_sdio_remove(struct mmc_host *host) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci int i; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci for (i = 0;i < host->card->sdio_funcs;i++) { 9158c2ecf20Sopenharmony_ci if (host->card->sdio_func[i]) { 9168c2ecf20Sopenharmony_ci sdio_remove_func(host->card->sdio_func[i]); 9178c2ecf20Sopenharmony_ci host->card->sdio_func[i] = NULL; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci mmc_remove_card(host->card); 9228c2ecf20Sopenharmony_ci host->card = NULL; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci/* 9268c2ecf20Sopenharmony_ci * Card detection - card is alive. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_cistatic int mmc_sdio_alive(struct mmc_host *host) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci return mmc_select_card(host->card); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/* 9348c2ecf20Sopenharmony_ci * Card detection callback from host. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_cistatic void mmc_sdio_detect(struct mmc_host *host) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci int err; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Make sure card is powered before detecting it */ 9418c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) { 9428c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(&host->card->dev); 9438c2ecf20Sopenharmony_ci if (err < 0) { 9448c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&host->card->dev); 9458c2ecf20Sopenharmony_ci goto out; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci mmc_claim_host(host); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* 9528c2ecf20Sopenharmony_ci * Just check if our card has been removed. 9538c2ecf20Sopenharmony_ci */ 9548c2ecf20Sopenharmony_ci err = _mmc_detect_card_removed(host); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci mmc_release_host(host); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * Tell PM core it's OK to power off the card now. 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * The _sync variant is used in order to ensure that the card 9628c2ecf20Sopenharmony_ci * is left powered off in case an error occurred, and the card 9638c2ecf20Sopenharmony_ci * is going to be removed. 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * Since there is no specific reason to believe a new user 9668c2ecf20Sopenharmony_ci * is about to show up at this point, the _sync variant is 9678c2ecf20Sopenharmony_ci * desirable anyway. 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) 9708c2ecf20Sopenharmony_ci pm_runtime_put_sync(&host->card->dev); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ciout: 9738c2ecf20Sopenharmony_ci if (err) { 9748c2ecf20Sopenharmony_ci mmc_sdio_remove(host); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci mmc_claim_host(host); 9778c2ecf20Sopenharmony_ci mmc_detach_bus(host); 9788c2ecf20Sopenharmony_ci mmc_power_off(host); 9798c2ecf20Sopenharmony_ci mmc_release_host(host); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* 9848c2ecf20Sopenharmony_ci * SDIO pre_suspend. We need to suspend all functions separately. 9858c2ecf20Sopenharmony_ci * Therefore all registered functions must have drivers with suspend 9868c2ecf20Sopenharmony_ci * and resume methods. Failing that we simply remove the whole card. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_cistatic int mmc_sdio_pre_suspend(struct mmc_host *host) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci int i; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci for (i = 0; i < host->card->sdio_funcs; i++) { 9938c2ecf20Sopenharmony_ci struct sdio_func *func = host->card->sdio_func[i]; 9948c2ecf20Sopenharmony_ci if (func && sdio_func_present(func) && func->dev.driver) { 9958c2ecf20Sopenharmony_ci const struct dev_pm_ops *pmops = func->dev.driver->pm; 9968c2ecf20Sopenharmony_ci if (!pmops || !pmops->suspend || !pmops->resume) 9978c2ecf20Sopenharmony_ci /* force removal of entire card in that case */ 9988c2ecf20Sopenharmony_ci goto remove; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ciremove: 10058c2ecf20Sopenharmony_ci if (!mmc_card_is_removable(host)) { 10068c2ecf20Sopenharmony_ci dev_warn(mmc_dev(host), 10078c2ecf20Sopenharmony_ci "missing suspend/resume ops for non-removable SDIO card\n"); 10088c2ecf20Sopenharmony_ci /* Don't remove a non-removable card - we can't re-detect it. */ 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Remove the SDIO card and let it be re-detected later on. */ 10138c2ecf20Sopenharmony_ci mmc_sdio_remove(host); 10148c2ecf20Sopenharmony_ci mmc_claim_host(host); 10158c2ecf20Sopenharmony_ci mmc_detach_bus(host); 10168c2ecf20Sopenharmony_ci mmc_power_off(host); 10178c2ecf20Sopenharmony_ci mmc_release_host(host); 10188c2ecf20Sopenharmony_ci host->pm_flags = 0; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci/* 10248c2ecf20Sopenharmony_ci * SDIO suspend. Suspend all functions separately. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_cistatic int mmc_sdio_suspend(struct mmc_host *host) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci WARN_ON(host->sdio_irqs && !mmc_card_keep_power(host)); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Prevent processing of SDIO IRQs in suspended state. */ 10318c2ecf20Sopenharmony_ci mmc_card_set_suspended(host->card); 10328c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&host->sdio_irq_work); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci mmc_claim_host(host); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) 10378c2ecf20Sopenharmony_ci sdio_disable_4bit_bus(host->card); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (!mmc_card_keep_power(host)) { 10408c2ecf20Sopenharmony_ci mmc_power_off(host); 10418c2ecf20Sopenharmony_ci } else if (host->retune_period) { 10428c2ecf20Sopenharmony_ci mmc_retune_timer_stop(host); 10438c2ecf20Sopenharmony_ci mmc_retune_needed(host); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci mmc_release_host(host); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic int mmc_sdio_resume(struct mmc_host *host) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci int err = 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* Basic card reinitialization. */ 10568c2ecf20Sopenharmony_ci mmc_claim_host(host); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* 10598c2ecf20Sopenharmony_ci * Restore power and reinitialize the card when needed. Note that a 10608c2ecf20Sopenharmony_ci * removable card is checked from a detect work later on in the resume 10618c2ecf20Sopenharmony_ci * process. 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci if (!mmc_card_keep_power(host)) { 10648c2ecf20Sopenharmony_ci mmc_power_up(host, host->card->ocr); 10658c2ecf20Sopenharmony_ci /* 10668c2ecf20Sopenharmony_ci * Tell runtime PM core we just powered up the card, 10678c2ecf20Sopenharmony_ci * since it still believes the card is powered off. 10688c2ecf20Sopenharmony_ci * Note that currently runtime PM is only enabled 10698c2ecf20Sopenharmony_ci * for SDIO cards that are MMC_CAP_POWER_OFF_CARD 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) { 10728c2ecf20Sopenharmony_ci pm_runtime_disable(&host->card->dev); 10738c2ecf20Sopenharmony_ci pm_runtime_set_active(&host->card->dev); 10748c2ecf20Sopenharmony_ci pm_runtime_enable(&host->card->dev); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci err = mmc_sdio_reinit_card(host); 10778c2ecf20Sopenharmony_ci } else if (mmc_card_wake_sdio_irq(host)) { 10788c2ecf20Sopenharmony_ci /* 10798c2ecf20Sopenharmony_ci * We may have switched to 1-bit mode during suspend, 10808c2ecf20Sopenharmony_ci * need to hold retuning, because tuning only supprt 10818c2ecf20Sopenharmony_ci * 4-bit mode or 8 bit mode. 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci mmc_retune_hold_now(host); 10848c2ecf20Sopenharmony_ci err = sdio_enable_4bit_bus(host->card); 10858c2ecf20Sopenharmony_ci mmc_retune_release(host); 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (err) 10898c2ecf20Sopenharmony_ci goto out; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* Allow SDIO IRQs to be processed again. */ 10928c2ecf20Sopenharmony_ci mmc_card_clr_suspended(host->card); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (host->sdio_irqs) { 10958c2ecf20Sopenharmony_ci if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) 10968c2ecf20Sopenharmony_ci wake_up_process(host->sdio_irq_thread); 10978c2ecf20Sopenharmony_ci else if (host->caps & MMC_CAP_SDIO_IRQ) 10988c2ecf20Sopenharmony_ci queue_delayed_work(system_wq, &host->sdio_irq_work, 0); 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ciout: 11028c2ecf20Sopenharmony_ci mmc_release_host(host); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci host->pm_flags &= ~MMC_PM_KEEP_POWER; 11058c2ecf20Sopenharmony_ci return err; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int mmc_sdio_runtime_suspend(struct mmc_host *host) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci /* No references to the card, cut the power to it. */ 11118c2ecf20Sopenharmony_ci mmc_claim_host(host); 11128c2ecf20Sopenharmony_ci mmc_power_off(host); 11138c2ecf20Sopenharmony_ci mmc_release_host(host); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci return 0; 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic int mmc_sdio_runtime_resume(struct mmc_host *host) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci int ret; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Restore power and re-initialize. */ 11238c2ecf20Sopenharmony_ci mmc_claim_host(host); 11248c2ecf20Sopenharmony_ci mmc_power_up(host, host->card->ocr); 11258c2ecf20Sopenharmony_ci ret = mmc_sdio_reinit_card(host); 11268c2ecf20Sopenharmony_ci mmc_release_host(host); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return ret; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/* 11328c2ecf20Sopenharmony_ci * SDIO HW reset 11338c2ecf20Sopenharmony_ci * 11348c2ecf20Sopenharmony_ci * Returns 0 if the HW reset was executed synchronously, returns 1 if the HW 11358c2ecf20Sopenharmony_ci * reset was asynchronously scheduled, else a negative error code. 11368c2ecf20Sopenharmony_ci */ 11378c2ecf20Sopenharmony_cistatic int mmc_sdio_hw_reset(struct mmc_host *host) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct mmc_card *card = host->card; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* 11428c2ecf20Sopenharmony_ci * In case the card is shared among multiple func drivers, reset the 11438c2ecf20Sopenharmony_ci * card through a rescan work. In this way it will be removed and 11448c2ecf20Sopenharmony_ci * re-detected, thus all func drivers becomes informed about it. 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ci if (atomic_read(&card->sdio_funcs_probed) > 1) { 11478c2ecf20Sopenharmony_ci if (mmc_card_removed(card)) 11488c2ecf20Sopenharmony_ci return 1; 11498c2ecf20Sopenharmony_ci host->rescan_entered = 0; 11508c2ecf20Sopenharmony_ci mmc_card_set_removed(card); 11518c2ecf20Sopenharmony_ci _mmc_detect_change(host, 0, false); 11528c2ecf20Sopenharmony_ci return 1; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * A single func driver has been probed, then let's skip the heavy 11578c2ecf20Sopenharmony_ci * hotplug dance above and execute the reset immediately. 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci mmc_power_cycle(host, card->ocr); 11608c2ecf20Sopenharmony_ci return mmc_sdio_reinit_card(host); 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic int mmc_sdio_sw_reset(struct mmc_host *host) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci mmc_set_clock(host, host->f_init); 11668c2ecf20Sopenharmony_ci sdio_reset(host); 11678c2ecf20Sopenharmony_ci mmc_go_idle(host); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci mmc_set_initial_state(host); 11708c2ecf20Sopenharmony_ci mmc_set_initial_signal_voltage(host); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci return mmc_sdio_reinit_card(host); 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic const struct mmc_bus_ops mmc_sdio_ops = { 11768c2ecf20Sopenharmony_ci .remove = mmc_sdio_remove, 11778c2ecf20Sopenharmony_ci .detect = mmc_sdio_detect, 11788c2ecf20Sopenharmony_ci .pre_suspend = mmc_sdio_pre_suspend, 11798c2ecf20Sopenharmony_ci .suspend = mmc_sdio_suspend, 11808c2ecf20Sopenharmony_ci .resume = mmc_sdio_resume, 11818c2ecf20Sopenharmony_ci .runtime_suspend = mmc_sdio_runtime_suspend, 11828c2ecf20Sopenharmony_ci .runtime_resume = mmc_sdio_runtime_resume, 11838c2ecf20Sopenharmony_ci .alive = mmc_sdio_alive, 11848c2ecf20Sopenharmony_ci .hw_reset = mmc_sdio_hw_reset, 11858c2ecf20Sopenharmony_ci .sw_reset = mmc_sdio_sw_reset, 11868c2ecf20Sopenharmony_ci}; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci/* 11908c2ecf20Sopenharmony_ci * Starting point for SDIO card init. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ciint mmc_attach_sdio(struct mmc_host *host) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci int err, i, funcs; 11958c2ecf20Sopenharmony_ci u32 ocr, rocr; 11968c2ecf20Sopenharmony_ci struct mmc_card *card; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci WARN_ON(!host->claimed); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci err = mmc_send_io_op_cond(host, 0, &ocr); 12018c2ecf20Sopenharmony_ci if (err) 12028c2ecf20Sopenharmony_ci return err; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci mmc_attach_bus(host, &mmc_sdio_ops); 12058c2ecf20Sopenharmony_ci if (host->ocr_avail_sdio) 12068c2ecf20Sopenharmony_ci host->ocr_avail = host->ocr_avail_sdio; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci rocr = mmc_select_voltage(host, ocr); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* 12128c2ecf20Sopenharmony_ci * Can we support the voltage(s) of the card(s)? 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_ci if (!rocr) { 12158c2ecf20Sopenharmony_ci err = -EINVAL; 12168c2ecf20Sopenharmony_ci goto err; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* 12208c2ecf20Sopenharmony_ci * Detect and init the card. 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci err = mmc_sdio_init_card(host, rocr, NULL); 12238c2ecf20Sopenharmony_ci if (err) 12248c2ecf20Sopenharmony_ci goto err; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci card = host->card; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* 12298c2ecf20Sopenharmony_ci * Enable runtime PM only if supported by host+card+board 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) { 12328c2ecf20Sopenharmony_ci /* 12338c2ecf20Sopenharmony_ci * Do not allow runtime suspend until after SDIO function 12348c2ecf20Sopenharmony_ci * devices are added. 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&card->dev); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* 12398c2ecf20Sopenharmony_ci * Let runtime PM core know our card is active 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci err = pm_runtime_set_active(&card->dev); 12428c2ecf20Sopenharmony_ci if (err) 12438c2ecf20Sopenharmony_ci goto remove; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * Enable runtime PM for this card 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci pm_runtime_enable(&card->dev); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* 12528c2ecf20Sopenharmony_ci * The number of functions on the card is encoded inside 12538c2ecf20Sopenharmony_ci * the ocr. 12548c2ecf20Sopenharmony_ci */ 12558c2ecf20Sopenharmony_ci funcs = (ocr & 0x70000000) >> 28; 12568c2ecf20Sopenharmony_ci card->sdio_funcs = 0; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* 12598c2ecf20Sopenharmony_ci * Initialize (but don't add) all present functions. 12608c2ecf20Sopenharmony_ci */ 12618c2ecf20Sopenharmony_ci for (i = 0; i < funcs; i++, card->sdio_funcs++) { 12628c2ecf20Sopenharmony_ci err = sdio_init_func(host->card, i + 1); 12638c2ecf20Sopenharmony_ci if (err) 12648c2ecf20Sopenharmony_ci goto remove; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci /* 12678c2ecf20Sopenharmony_ci * Enable Runtime PM for this func (if supported) 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) 12708c2ecf20Sopenharmony_ci pm_runtime_enable(&card->sdio_func[i]->dev); 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * First add the card to the driver model... 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci mmc_release_host(host); 12778c2ecf20Sopenharmony_ci err = mmc_add_card(host->card); 12788c2ecf20Sopenharmony_ci if (err) 12798c2ecf20Sopenharmony_ci goto remove_added; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* 12828c2ecf20Sopenharmony_ci * ...then the SDIO functions. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci for (i = 0;i < funcs;i++) { 12858c2ecf20Sopenharmony_ci err = sdio_add_func(host->card->sdio_func[i]); 12868c2ecf20Sopenharmony_ci if (err) 12878c2ecf20Sopenharmony_ci goto remove_added; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (host->caps & MMC_CAP_POWER_OFF_CARD) 12918c2ecf20Sopenharmony_ci pm_runtime_put(&card->dev); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci mmc_claim_host(host); 12948c2ecf20Sopenharmony_ci return 0; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ciremove: 12988c2ecf20Sopenharmony_ci mmc_release_host(host); 12998c2ecf20Sopenharmony_ciremove_added: 13008c2ecf20Sopenharmony_ci /* 13018c2ecf20Sopenharmony_ci * The devices are being deleted so it is not necessary to disable 13028c2ecf20Sopenharmony_ci * runtime PM. Similarly we also don't pm_runtime_put() the SDIO card 13038c2ecf20Sopenharmony_ci * because it needs to be active to remove any function devices that 13048c2ecf20Sopenharmony_ci * were probed, and after that it gets deleted. 13058c2ecf20Sopenharmony_ci */ 13068c2ecf20Sopenharmony_ci mmc_sdio_remove(host); 13078c2ecf20Sopenharmony_ci mmc_claim_host(host); 13088c2ecf20Sopenharmony_cierr: 13098c2ecf20Sopenharmony_ci mmc_detach_bus(host); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci pr_err("%s: error %d whilst initialising SDIO card\n", 13128c2ecf20Sopenharmony_ci mmc_hostname(host), err); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return err; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 1317