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