(1)串行外设接口(SPI:Serial Peripheral interface)是一种串行同步通讯协议(同时读入和写出),由SDI(串行数据输入),SDO(串行数据输出),SCK(串行移位时钟),CS(从使能信号)四种信号构成。CS 决定了唯一的与主设备通信的从设备,如没有CS 信号,则只能存在一个从设备,主设备通过产生移位时钟来发起通讯。
主要影响SPI通讯的两个参数是时钟极性(CPOL)和时钟相位(CPHA)两个参数,SPI传输串行数据时首先传输最高位。时钟极性(CPOL)对传输协议没有重大的影响,如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输,如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。图示如下:
一般的ARM系统对SPI的支持方式分三种:轮询(POLLING),中断(INTERRUPT,需要定义SPI的中断号),和DMA(配置好SPI和DMA对应的寄存器,和DMA的源头和目的地址,就可以开始进行DMA传输)。
(2)基于SDIO协议,SD卡的定义如下:
上图是以CD/DAT3的复用来实现卡检测功能,其实CD可以以单独的GPIO中断来实现,但本质上CD是可有可无的,因为很多应用场合并不需要支持SD热插拔。至于SD唤醒系统,也是由GPIO中断来实现,也可以定义数据线中断来实现(如果SDIO数据线协议支持的话)。
SDIO协议可以支持三种操作模式:SPI,SD一线,SD四线(接口通过寄存器来配置)。SPI速度较低,一线或者四线需要寄存器来选择,高速模式下需要四线支持。其中DAT是数据线,一线模式下默认用DAT0;CMD线上传输串行命令,可以是单机寻址或者广播命令。
=================================================================================================================
6410平台对SD卡的支持,表现在CH0(CH1被用来连接WIFI,和CH0共一个DETECT脚,即XmmcCDN0),添加HSMMC设备,分配对应资源即可。
(1)
static struct platform_device *smdk6410_devices[] __initdata = {
........
&s3c_device_hsmmc0,
........
}
定义如下:
struct platform_device s3c_device_hsmmc0 = {
.name = "s3c-sdhci",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_hsmmc_resource),
.resource = s3c_hsmmc_resource,
.dev = {
.dma_mask = &s3c_device_hsmmc_dmamask,
.coherent_dma_mask = 0xffffffffUL,
.platform_data = &s3c_hsmmc0_def_platdata,
},
};
调用如下:
static u64 s3c_device_hsmmc_dmamask = 0xffffffffUL;
struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = {
.max_width = 4,
.host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SD_HIGHSPEED),
};
(2)
完善s3c_hsmmc0_def_platdata 的配置,在
static inline void s3c6410_default_sdhci0(void)
{
s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s3c6410_setup_sdhci0_cfg_gpio;
s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
}
在s3c6410_setup_sdhci0_cfg_gpio这个函数中,对XmmcCDN0进行了配置,使其只能单独用在MMC0或MMC1,此处用在MMC0上检测SD卡的热插拔:
s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
对应的在s3c6410_setup_sdhci1_cfg_gpio里面就要屏蔽掉这些东西。
补充:在函数void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)中的width参数是用来配置1线还是4线模式的。在最开始的时候,mmc控制器不知道是什么卡,所以传进来的width就是1,这样就只初始化cmd和clk,仅仅保证可以识别出来,在识别出卡的类型后在传具体的width进来,比如4或者1来配置。这个过程在sdhci-s3c-sdio.c中。
(3)
以上是platform device,则dirver在sdhci-s3c.c调用如下:
static struct platform_driver sdhci_s3c_driver = {
.probe = sdhci_s3c_probe,
.suspend = sdhci_s3c_suspend,
.resume = sdhci_s3c_resume,
.remove = __devexit_p(sdhci_s3c_remove),
.driver = {
.owner = THIS_MODULE,
.name = "s3c-sdhci",
},
};
在初始化模块时用platform_driver_register(&sdhci_s3c_driver)即可。