资讯详情

Linux内核4.14版本——mmc core(7)——mmc core主模块(3)总线io setting相关(struct mmc_ios)

1. mmc_ios说明

2.mmc_set_ios

3. mmc_set_bus_mode & mmc_set_bus_width


1. mmc_ios说明

struct mmc_ios 由mmc core定义的标准结构用于维护mmc一些与总线相关的io setting。如下:

struct mmc_ios {	unsigned int	clock;			/* clock rate */	unsigned short	vdd;/* vdd stores the bit number of the selected voltage range from below. */	unsigned char	bus_mode;		/* command output mode */#define MMC_BUSMODE_OPENDRAIN	1#define MMC_BUSMODE_PUSHPULL	2	unsigned char	chip_select;		/* SPI chip select */#define MMC_CS_DONTCARE		0#define MMC_CS_HIGH		1#define MMC_CS_LOW		2	unsigned char	power_mode;		/* power supply mode */#define MMC_POWER_OFF		0#define MMC_POWER_UP		1#define MMC_POWER_ON		2#define MMC_POWER_UNDEFINED	3	unsigned char	bus_width;		/* data bus width */#define MMC_BUS_WIDTH_1		0#define MMC_BUS_WIDTH_4		2#define MMC_BUS_WIDTH_8		3	unsigned char	timing;			/* timing specification used */#define MMC_TIMING_LEGACY	0#define MMC_TIMING_MMC_HS	1#define MMC_TIMING_SD_HS	2#define MMC_TIMING_UHS_SDR12	3#define MMC_TIMING_UHS_SDR25	4#define MMC_TIMING_UHS_SDR50	5#define MMC_TIMING_UHS_SDR104	6#define MMC_TIMING_UHS_DDR50	7#define MMC_TIMING_MMC_DDR52	8#define MMC_TIMING_MMC_HS200	9#define MMC_TIMING_MMC_HS400	10	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */#define MMC_SIGNAL_VOLTAGE_330	0#define MMC_SIGNAL_VOLTAGE_180	1#define MMC_SIGNAL_VOLTAGE_120	2	unsigned char	drv_type;		/* driver type (A,B,C,D) */#define MMC_SET_DRIVER_TYPE_B	0#define MMC_SET_DRIVER_TYPE_A	1#define MMC_SET_DRIVER_TYPE_C	2#define MMC_SET_DRIVER_TYPE_D	3	bool enhanced_strobe;			/* hs400es selection */};

1)clock,时钟频率。

2)vdd,通过1 << vdd”可以得到MMC_VDD_x_x(详见参考include/linux/mmc/host.h中MMC_VDD_开头的定义),然后获取电压信息。

3)bus_mode,两种信号模式,open-drain(MMC_BUSMODE_OPENDRAIN)和push-pull(MMC_BUSMODE_PUSHPULL),对应不同的高低电平(可参考相应的高低电平)spec,例如[2]。

4)chip_select,只针对SPI指定片选信号的有效模式,包括无片选信号(MMC_CS_DONTCARE)、高电平有效(MMC_CS_HIGH)、低电平有效(MMC_CS_LOW)。

5)power_mode,当前的电源状态包括MMC_POWER_OFF、MMC_POWER_UP、MMC_POWER_ON和MMC_POWER_UNDEFINED。

6)bus_width,总线宽度,包括1-bit(MMC_BUS_WIDTH_1)、4-bit(MMC_BUS_WIDTH_4)和8-bit(MMC_BUS_WIDTH_8)。

7)timing,符合哪种总线时序(大多对应某一类)MMC包括:

MMC_TIMING_LEGACY,旧的、不再使用的规范; MMC_TIMING_MMC_HS,High speed MMC规范(详见相应规范)spec,这里不再详细介绍,下同); MMC_TIMING_SD_HS,High speed SD; MMC_TIMING_UHS_SDR12; MMC_TIMING_UHS_SDR25 MMC_TIMING_UHS_SDR50 MMC_TIMING_UHS_SDR104 MMC_TIMING_UHS_DDR50 MMC_TIMING_MMC_DDR52 MMC_TIMING_MMC_HS200 MMC_TIMING_MMC_HS400

8)signal_voltage,总线信号使用哪一种电压,3.3v(MMC_SIGNAL_VOLTAGE_330)、1.8v(MMC_SIGNAL_VOLTAGE_180)或者1.2v(MMC_SIGNAL_VOLTAGE_120)。

9)drv_type,驱动能力包括:

MMC_SET_DRIVER_TYPE_B MMC_SET_DRIVER_TYPE_A MMC_SET_DRIVER_TYPE_C MMC_SET_DRIVER_TYPE_D

2.mmc_set_ios

统一设置mmc总线的io设置(io setting)。

static inline void mmc_set_ios(struct mmc_host *host){	struct mmc_ios *ios = &host->ios;	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "		"width %u timing %u\n",		 mmc_hostname(host),ios->clock,ios->bus_mode,		 ios->power_mode,ios->chip_select,ios->vdd,		 1 << ios->bus_width,ios->timing);	host->ops->set_ios(host,ios);}

会调用host->ops->set_ios来对mmc总线的io setting设置,核心函数。sdhci类型的host,对应就是sdhci_set_ios(drivers\mmc\host\sdhci.c)。

void sdhci_set_ios(struct mmc_host *mmc,struct mmc_ios *ios){	struct sdhci_host *host = mmc_priv(mmc);	u8 ctrl;	if (ios->power_mode == MMC_POWER_UNDEFINED)		return;	if (host->flags & SDHCI_DEVICE_DEAD) {		if (!IS_ERR(mmc->supply.vmmc) &&		    ios->power_mode == MMC_POWER_OFF)			mmc_regulator_set_ocr(mmc,mmc->supply.vmmc,0);		return;	}	/*	 * Reset the chip on each power off.	 * Should clear out any weird states.	 */	if (ios->power_mode == MMC_POWER_OFF) {		sdhci_writel(host,0,SDHCI_SIGNAL_ENABLE);		sdhci_reinit(host);	}	if (host->version >= SDHCI_SPEC_300 &&		(ios->power_mode == MMC_POWER_UP) &&		!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))		sdhci_enable_preset_value(host,false);	if (!ios->clock || ios->clock != host->clock) {		host->ops->set_clock(host, ios->clock);		host->clock = ios->clock;		if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&		    host->clock) {			host->timeout_clk = host->mmc->actual_clock ?						host->mmc->actual_clock / 1000 :						host->clock / 1000;			host->mmc->max_busy_timeout =				host->ops->get_max_timeout_count ?				host->ops->get_max_timeout_count(host) :				1 << 27;			host->mmc->max_busy_timeout /= host->timeout_clk;		}	}	if (host->ops->set_power)		host->ops->set_power(host, ios->power_mode, ios->vdd);	else		sdhci_set_power(host, ios->power_mode, ios->vdd);	if (host->ops->platform_send_init_74_clocks)		host->ops->platform_send_init_74_clocks(host, ios->power_mode);	host->ops->set_bus_width(host, ios->bus_width);	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);	if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {		if (ios->timing == MMC_TIMING_SD_HS ||		     ios->timing == MMC_TIMING_MMC_HS ||		     ios->timing == MMC_TIMING_MMC_HS400 ||		     ios->timing == MMC_TIMING_MMC_HS200 ||		     ios->timing == MMC_TIMING_MMC_DDR52 ||		     ios->timing == MMC_TIMING_UHS_SDR50 ||		     ios->timing == MMC_TIMING_UHS_SDR104 ||		     ios->timing == MMC_TIMING_UHS_DDR50 ||		     ios->timing == MMC_TIMING_UHS_SDR25)			ctrl |= SDHCI_CTRL_HISPD;		else			ctrl &= ~SDHCI_CTRL_HISPD;	}	if (host->version >= SDHCI_SPEC_300) {		u16 clk, ctrl_2;		if (!host->preset_enabled) {			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);			/*			 * We only need to set Driver Strength if the			 * preset value enable is not set.			 */			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);			ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;			if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;			else if (ios->drv_type == MMC_SET_DRIVER_TYPE_B)				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;			else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;			else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;			else {				pr_warn("%s: invalid driver type, default to driver type B\n",					mmc_hostname(mmc));				ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;			}			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);		} else {			/*			 * According to SDHC Spec v3.00, if the Preset Value			 * Enable in the Host Control 2 register is set, we			 * need to reset SD Clock Enable before changing High			 * Speed Enable to avoid generating clock gliches.			 */			/* Reset SD Clock Enable */			clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);			clk &= ~SDHCI_CLOCK_CARD_EN;			sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);			sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);			/* Re-enable SD Clock */			host->ops->set_clock(host, host->clock);		}		/* Reset SD Clock Enable */		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);		clk &= ~SDHCI_CLOCK_CARD_EN;		sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);		host->ops->set_uhs_signaling(host, ios->timing);		host->timing = ios->timing;		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&				((ios->timing == MMC_TIMING_UHS_SDR12) ||				 (ios->timing == MMC_TIMING_UHS_SDR25) ||				 (ios->timing == MMC_TIMING_UHS_SDR50) ||				 (ios->timing == MMC_TIMING_UHS_SDR104) ||				 (ios->timing == MMC_TIMING_UHS_DDR50) ||				 (ios->timing == MMC_TIMING_MMC_DDR52))) {			u16 preset;			sdhci_enable_preset_value(host, true);			preset = sdhci_get_preset_value(host);			ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)				>> SDHCI_PRESET_DRV_SHIFT;		}		/* Re-enable SD Clock */		host->ops->set_clock(host, host->clock);	} else		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);	/*	 * Some (ENE) controllers go apeshit on some ios operation,	 * signalling timeout and CRC errors even on CMD0. Resetting	 * it on each ios seems to solve the problem.	 */	if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)		sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);	mmiowb();}

3. mmc_set_bus_mode & mmc_set_bus_width

mmc_set_bus_mode用于设置总线模式,有如下模式

MMC_BUSMODE_OPENDRAIN(开漏模式) MMC_BUSMODE_PUSHPULL(上拉模式)

mmc_set_bus_width用于设置总线宽度,有如下模式

MMC_BUS_WIDTH_1 MMC_BUS_WIDTH_4 MMC_BUS_WIDTH_8

/* * Change the bus mode (open drain/push-pull) of a host. */void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode){	host->ios.bus_mode = mode;	mmc_set_ios(host);}/* * Change data bus width of a host. */void mmc_set_bus_width(struct mmc_host *host, unsigned int width){	host->ios.bus_width = width;	mmc_set_ios(host);}

标签: uhz液位变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司