1. 程式人生 > >SDIO驅動(1)從驅動模型的角度看Host驅動

SDIO驅動(1)從驅動模型的角度看Host驅動

開宗明義:


一、SDIO概述

The SDIO (SD Input/Output) card is based on and compatible with the SD memory card. This compatibility
includes mechanical, electrical, power, signaling and software.

The intent of the SDIO card is to provide high-speed data I/O with low power consumption for mobile electronic devices.
A primary goal is that an SDIO card inserted into a non-SDIO aware host shall cause no physical damage or disruption of 
that host or it’s software. In this case, the SDIO card should simply be ignored. 

Once inserted into an SDIO aware host, the detection of the card proceeds via the normal means described in 
this specification with some extensions. In this state, the SDIO card is idle and draws a small amount of power (15 mA averaged
over 1 second). 

During the normal initialization and interrogation of the card by the host, the card identifies itself as an SDIO card. The host
software then obtains the card information in a tuple (linked list) format and determines if that card’s I/O
function(s) are acceptable to activate. This decision is based on such parameters as power requirements or the
availability of appropriate software drivers. 

If the card is acceptable, it is allowed to power up fully and start the I/O function(s) built into it.

簡單來說:

1、SDIO起源於SD標準,專注於實現IO資料收發

2、基於設計的通用性,對於不支援的操作(CMD),裝置可以選擇忽視但不應產生異常

3、SD起源於MMC,所以想要初步瞭解下SDIO的話,參見:

4、SDIO應用越來越廣泛,常用裝置如:WiFi、GSP、Camera等

由於MMC、SD、SDIO溯本同源,所以在Linux中統一歸於mmc,目錄:


mmc框架,簡單描述如下:


Host driver就是驅動Soc上的Host Controller,這就離不開具體的Soc,我們以s3c2440為例說明。

二、SDIO HOST之bus

Linux驅動模型(kernel/Documentation/driver-model)
device、bus、driver、class。Bus屬於MMC框架的範疇,對於此類外設,掛在SDIO總線上:
static struct bus_type sdio_bus_type = {
	.name		= "sdio",
	.dev_attrs	= sdio_dev_attrs,
	.match		= sdio_bus_match,
	.uevent		= sdio_bus_uevent,
	.probe		= sdio_bus_probe,
	.remove		= sdio_bus_remove,
	.pm		= SDIO_PM_OPS_PTR,
};
match負責device和driver的匹配工作,檢視掛在SDIO上的device/driver:
# ls -l /sys/bus/sdio/                                     
drwxr-xr-x root     root              2017-04-23 17:25 devices
drwxr-xr-x root     root              2017-04-23 17:25 drivers
-rw-r--r-- root     root         4096 2017-04-23 17:25 drivers_autoprobe
--w------- root     root         4096 2017-04-23 17:25 drivers_probe
--w------- root     root         4096 2017-04-23 17:25 uevent

三、SDIO HOST之device

device作為Host,其描述:

struct platform_device s3c_device_sdi = {
	.name		  = "s3c2410-sdi",
	.id		  = -1,
	.num_resources	  = ARRAY_SIZE(s3c_sdi_resource),
	.resource	  = s3c_sdi_resource,
};

Host佔用的資源:

static struct resource s3c_sdi_resource[] = {
	[0] = {
		.start = S3C24XX_PA_SDI,
		.end   = S3C24XX_PA_SDI + S3C24XX_SZ_SDI - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_SDI,
		.end   = IRQ_SDI,
		.flags = IORESOURCE_IRQ,
	}
};

以上指定Host的資源型別(mem、irq)資源和各個資源的具體分配情況。

在系統啟動的過程中,進行plateform裝置的註冊,註冊流程如下:

MACHINE_START(S3C2440, "S3C2440")
	.init_machine	= s3c2440_machine_init,
MACHINE_END

s3c2440_machine_init
	->platform_add_devices(s3c2440_devices, ARRAY_SIZE(s3c2440_devices));
	
static struct platform_device *s3c2440_devices[] __initdata = {
	...
	&s3c_device_sdi,
};

註冊成功後,可以在/sys/bus/platform/devices目錄檢視對應裝置的資訊。

四、SDIO HOST之driver

自然,操作SDIO控制器的就是平臺驅動:platform_driver

s3cmci.c (g:\linux-2.6.38.6\drivers\mmc\host)
static struct platform_driver s3cmci_driver = {
	.driver	= {
		.name	= "s3c-sdi",
		.owner	= THIS_MODULE,
		.pm	= s3cmci_pm_ops,
	},
	.id_table	= s3cmci_driver_ids,
	.probe		= s3cmci_probe,
	.remove		= __devexit_p(s3cmci_remove),
	.shutdown	= s3cmci_shutdown,
};

載入驅動的時候,在probe過程中解析device的屬性並進行配置

如果probe過程順利成功,SDIO controller作為Host被新增到系統

static int __devinit s3cmci_probe(struct platform_device *pdev)
{
	struct s3cmci_host *host;
	struct mmc_host	*mmc;

	// 建立mmc_host(物件),在mmc_alloc_host()中進行一些通用設定的初始化
	mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);

	// s3cmci_host(物件)作為mmc_host的私有資料存在,這樣通過mmc_host(物件)就可以
	// 方便的獲取s3cmci_host並對其進行操作
	host = mmc_priv(mmc);
	host->mmc 	= mmc;
	host->pdev	= pdev;

	// Host註冊
	ret = mmc_add_host(mmc);

	return 0;
}

現在,device和driver都有了,在裝置或驅動載入的時候由SDIO匯流排負責匹配:

device:
s3c_device_sdi.name  = "s3c2440-sdi";

driver:
static struct platform_device_id s3cmci_driver_ids[] = {
    {
        .name    = "s3c2440-sdi",
        .driver_data    = 1,
    },
};
神說:“‘要有光’,就有了光。”事情就這樣成了。

五、SDIO HOST之class

驅動模型中的class描述同一種類型的裝置,比如這裡的host,統一歸類到mmc_host類別下,mmc_host類的定義:

static struct class mmc_host_class = {
	.name		= "mmc_host",
	.dev_release	= mmc_host_classdev_release,
};
在初始化host的時候設定其class屬性:
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
	struct mmc_host *host;

	dev_set_name(&host->class_dev, "mmc%d", host->index);
	host->parent = dev;
	host->class_dev.parent = dev;
	host->class_dev.class = &mmc_host_class;
	device_initialize(&host->class_dev);

	return host;
}
host註冊成功後在sysfs下的呈現:
root@user:/sys/class # ls mmc_host/                                    
mmc0
mmc1
mmc2
上述顯示,我們的系統中有三個host。