SDIO驅動(9)Host註冊

    Linux 2.6.38  
    S3C2440  
SDIO驅動(8)Host驅動實現

第8行,mmc_alloc_host創建mmc host,並進行通用部分的初始化。第1個參數指定mmc_host對象中private數據佔用的內存大小,這裏把struct s3cmci_host對象設置爲了private數據。mmc_alloc_host函數很好看的:

/**
 *	mmc_alloc_host - initialise the per-host structure.
 *	@extra: sizeof private data structure
 *	@dev: pointer to host device model structure
 *
 *	Initialise the per-host structure.
 */
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
	int err;
	struct mmc_host *host;

	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
		return NULL;

	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
	if (!host)
		return NULL;

	spin_lock(&mmc_host_lock);
	err = idr_get_new(&mmc_host_idr, host, &host->index);
	spin_unlock(&mmc_host_lock);
	if (err)
		goto free;

	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);

	mmc_host_clk_init(host);

	spin_lock_init(&host->lock);
	init_waitqueue_head(&host->wq);
	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
	INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
#ifdef CONFIG_PM
	host->pm_notify.notifier_call = mmc_pm_notify;
#endif

	/*
	 * By default, hosts do not support SGIO or large requests.
	 * They have to set these according to their abilities.
	 */
	host->max_segs = 1;
	host->max_seg_size = PAGE_CACHE_SIZE;

	host->max_req_size = PAGE_CACHE_SIZE;
	host->max_blk_size = 512;
	host->max_blk_count = PAGE_CACHE_SIZE / 512;

	return host;

free:
	kfree(host);
	return NULL;
}

13~26行,idr_*函數用於從kernel獲取一個id,用於區分不同的host;28~31行初始化host這個設備並設置類別(class)爲“mmc_host”,設備添加後在class的mmc_host類別下可以看到這個設備:/sys/class/mmc_host/。

33行mmc_host_clk_init(host)用於設置bus的門控時鐘:

/**
 *	mmc_host_clk_init - set up clock gating code
 *	@host: host with potential clock to control
 */
static inline void mmc_host_clk_init(struct mmc_host *host)
{
	host->clk_requests = 0;
	/* Hold MCI clock for 8 cycles by default */
	host->clk_delay = 8;
	host->clk_gated = false;
	INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
	spin_lock_init(&host->clk_lock);
}
clock gate通過下圖就一目瞭然:


啓用了門控時鐘的功能我們就可以控制host的時鐘輸出,這是個涉及硬件的操作,所以具體實現還是由host controller決定(host成員mmc_host_ops的set_ios)。

mmc_alloc_host餘下的代碼初始化成員,其中host->detect用於卡掃描的一個work,host->disable禁用該host,notifier_call,休眠發生時向host發送通知。


14~24獲取host連接外部卡的pin。

26行開篇mmc_host爲對象private分配的內存用上了吧,內核中類似的使用比比皆是,之後通過struct s3cmci_host *host = mmc_priv(mmc)可以方便的獲取s3cmci_host進行操作。

37行host->pio_tasklet任務用來讀寫數據,是種下半部機制。中斷髮生後,中斷的handler只處理短小、緊急的事務(比如清除中斷標誌,此爲上半部);接着使用tasklet處理好事的事情,這樣提高了中斷的吞吐率。

39~43設置host controller的中斷/數據寄存器和分頻係數。

52~95獲取“ SDIO驅動(1)Host驅動框架”中定義好的mem、irq資源,中斷處理函數s3cmci_irq!驅動probe過程中,disable中斷功能。

97~122如果設置了card監測引腳,有卡插拔時引發一次scan動作(host->detect, mmc_rescan)。

124~132如果設置了寫保護引腳,寫數據是需要查詢host->pdata->gpio_wprotect的pin狀態,確定是否可以寫數據。

136~149獲取dma資源。

151~165行,host和card之間時鐘設置。

167行mmc->ops,host的操作接口,這裏:

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,
	.enable_sdio_irq = s3cmci_enable_sdio_irq,
};
簡單來說,request,一次請求的實現;set_ios,設置bus的參數;get_ro,獲取card的讀寫狀態(是一張read/write卡or read-only卡);get_cd,檢測卡是否存在;enable_sdio_irq,通過寄存器控制sdio中斷使能、禁止。這幾個函數可以sleep,有的耗時較長,用時小心。


mmc->ocr_avail,該host可支持的操作電壓範圍。

mmc->caps,該host支持的功能特性,比如這裏的數據位4bit,支持sdio中斷。

mmc->f_minf_max該host支持的時鐘頻率範圍,最小頻率、最大頻率。

198行主角,mmc_add_host:

/**
 *	mmc_add_host - initialise host hardware
 *	@host: mmc host
 *
 *	Register the host with the driver model. The host must be
 *	prepared to start servicing requests before this function
 *	completes.
 */
int mmc_add_host(struct mmc_host *host)
{
	int err;

	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
		!host->ops->enable_sdio_irq);

	led_trigger_register_simple(dev_name(&host->class_dev), &host->led);

	err = device_add(&host->class_dev);
	if (err)
		return err;

#ifdef CONFIG_DEBUG_FS
	mmc_add_host_debugfs(host);
#endif

	mmc_start_host(host);
	register_pm_notifier(&host->pm_notify);

	return 0;
}
主要做兩件事:host設備註冊(18行),啓動host並進行一次掃描(26行)。所以註釋提到,在調用這個函數之前要做好準備工作。


204行,debugfs文件系統相關的東東,如果系統支持debugfs,在/sys/kernel/debug/下有host的目錄,可以查詢host的信息。目錄名稱就是dev_set_name(&host->class_dev, "mmc%d", host->index)設置的device name,比如:

# ls /sys/kernel/debug/mmc0/                                  
clock
completed_events
ios
pending_events
regs
req
state

# cat /sys/kernel/debug/mmc0/ios                                                  <
clock:		52000000 Hz
vdd:		23 (3.5 ~ 3.6 V)
bus mode:	2 (push-pull)
chip select:	0 (don't care)
power mode:	2 (on)
bus width:	3 (8 bits)
timing spec:	1 (mmc high-speed)
signal voltage:	0 (3.30 V)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章