s3cmci的 io开关操作分析

s3cmciio开关操作分析

s3cmciio操作使用的数据结构

struct mmc_ios {

类型

名称

unsigned int

clock

时钟速率

unsigned short

vdd

电压

unsigned char

bus_mode

#define MMC_BUSMODE_OPENDRAIN 1

#define MMC_BUSMODE_PUSHPULL 2

unsigned char

chip_select

#define MMC_CS_DONTCARE 0

#define MMC_CS_HIGH 1

#define MMC_CS_LOW 2

unsigned char

power_mode

#define MMC_POWER_OFF 0

#define MMC_POWER_UP 1

#define MMC_POWER_ON 2

unsigned char

bus_width

#define MMC_BUS_WIDTH_1 0

#define MMC_BUS_WIDTH_4 2

unsigned char

timing

#define MMC_TIMING_LEGACY 0

#define MMC_TIMING_MMC_HS 1

#define MMC_TIMING_SD_HS 2



};

s3cmciio操作的处理函数

static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)

主要完成开电源和关电源时的各种寄存器的设置,该处理函数通过一个宿主机操作集(即一个struct mmc_host_ops结构)MMC核心层注册自己,这样MMC核心层在需要开关电源时即通过调用注册的宿主机操作集中的.set_ios指向函数来完成.

io操作的处理函数的注册

s3cmci的宿主机操作集:

static struct mmc_host_ops s3cmci_ops = {

.request = s3cmci_request,

.set_ios = s3cmci_set_ios,

.get_ro = s3cmci_get_ro,

.get_cd = s3cmci_card_present,

};

s3cmci平台驱动的.probe指向的函数处理中被注册

static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)

{

...

mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);

...

mmc->ops = &s3cmci_ops;

...

mmc_add_host(mmc);

}

关电操作

mmc_core.c

















s3cmci.c



首先调用MMC核心函数 mmc_power_off(...)在此函数设置关电时设置参数,然后经过一个内部函数mmc_set_ios(...)的转换,调用宿主机自己的set_ios函数来处理.核心层只做通用的参数设置,对于不同的硬件的处理,由具体硬件的驱动根据IO设置参数来完成实际硬件的操作.

具体的操作主要完成以几件关机操作:

  1. 关闭时钟输出管脚,S3C2410_GPE5

  2. 设置电压,如果平台设置有自己的set_power处理,则调用之,

  3. 关闭时钟.

static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)

{

// 取得宿主机的私有数据结构.

struct s3cmci_host *host = mmc_priv(mmc);

u32 mci_psc, mci_con;



/* Set the power state */

// 读取当前宿主机的控制寄存器内容 .

mci_con = readl(host->base + S3C2410_SDICON);



switch (ios->power_mode) {

...

case MMC_POWER_OFF://

default:

// 关闭时钟输出管脚,S3C2410_GPE5 0b10时用于SDCLK,现将其设为为0(输出)

s3c2410_gpio_setpin(S3C2410_GPE5, 0);

s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);

......

// 如果平台设置有自己的set_power处理,则调用之.用于设置电压值.

if (host->pdata->set_power)

host->pdata->set_power(ios->power_mode, ios->vdd);

break;

}

/******************************************************************/

/* 设置时钟 */

// 设置最大的预引比例因子, 使得 宿主机的时钟频率不小于ios->clock设定的值

for (mci_psc = 0; mci_psc < 255; mci_psc++) {

host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));



if (host->real_rate <= ios->clock)

break;

}

if (mci_psc > 255)

mci_psc = 255;

// 保存宿主机的预比例因子.并写寄存器.

host->prescaler = mci_psc;

writel(host->prescaler, host->base + S3C2410_SDIPRE);



/* If requested clock is 0, real_rate will be 0, too */

if (ios->clock == 0)

host->real_rate = 0;

// 判断时钟使能,如果 ios->clock设定的时钟频率为0,则关闭时钟输出.写入寄存器.

if (ios->clock)

mci_con |= S3C2410_SDICON_CLOCKTYPE;

else

mci_con &= ~S3C2410_SDICON_CLOCKTYPE;//SDCLK out disable.

// 写控制寄存器

writel(mci_con, host->base + S3C2410_SDICON);



/* 设置时钟完毕*/

/**********************************************************************/

.....

// 保存总线宽度 .

host->bus_width = ios->bus_width;

}

开电操作

mmc_core.c



















s3cmci.c



static void mmc_power_up(struct mmc_host *host)

{

// 获取电压设置的低位,这样就有方法得到最低的电压.

int bit = fls(host->ocr_avail) - 1;

host->ios.vdd = bit;



if (mmc_host_is_spi(host)) {

host->ios.chip_select = MMC_CS_HIGH;

host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;

} else {

host->ios.chip_select = MMC_CS_DONTCARE;

host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;

}

host->ios.power_mode = MMC_POWER_UP;

host->ios.bus_width = MMC_BUS_WIDTH_1;

host->ios.timing = MMC_TIMING_LEGACY;

// IO设置

mmc_set_ios(host);



// 等待到达最小的电压值.

// 等待两毫秒.

mmc_delay(2);



host->ios.clock = host->f_min;

host->ios.power_mode = MMC_POWER_ON;

// IO设置

mmc_set_ios(host);

// 等待至少74个时钟周期,或者一个足够的时间到达稳定电压.这里用2ms

mmc_delay(2);

}



static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)

{

// 取得宿主机的私有数据结构.

struct s3cmci_host *host = mmc_priv(mmc);

u32 mci_psc, mci_con;



/* Set the power state */

// 读取当前宿主机的控制寄存器内容 .

mci_con = readl(host->base + S3C2410_SDICON);



switch (ios->power_mode) {

case MMC_POWER_ON:

case MMC_POWER_UP:

// 设置SD卡的所有IO管脚功能

s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);

s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);

s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);

s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);

s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);

s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);

// 设置电压

if (host->pdata->set_power)

host->pdata->set_power(ios->power_mode, ios->vdd);



if (!host->is2440)

mci_con |= S3C2410_SDICON_FIFORESET;



break;

......

}

/******************************************************************/

/* 设置时钟 */

// 设置最大的预引比例因子, 使得 宿主机的时钟频率不小于ios->clock设定的值

for (mci_psc = 0; mci_psc < 255; mci_psc++) {

host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));



if (host->real_rate <= ios->clock)

break;

}

if (mci_psc > 255)

mci_psc = 255;

// 保存宿主机的预比例因子.并写寄存器.

host->prescaler = mci_psc;

writel(host->prescaler, host->base + S3C2410_SDIPRE);



/* If requested clock is 0, real_rate will be 0, too */

if (ios->clock == 0)

host->real_rate = 0;

// 判断时钟使能,如果 ios->clock设定的时钟频率为0,则关闭时钟输出.写入寄存器.

if (ios->clock)

mci_con |= S3C2410_SDICON_CLOCKTYPE;

else

mci_con &= ~S3C2410_SDICON_CLOCKTYPE;//SDCLK out disable.

// 写控制寄存器

writel(mci_con, host->base + S3C2410_SDICON);



/* 设置时钟完毕*/

/**********************************************************************/

.....

// 保存总线宽度 .

host->bus_width = ios->bus_width;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值