首页 > 编程知识 正文

sdio 驱动

时间:2023-05-04 13:12:31 阅读:260154 作者:1877

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_PMhost->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->hsjdc,该host支持的功能特性,比如这里的数据位4bit,支持sdio中断。

mmc->f_min、f_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->hsjdc & 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_FSmmc_add_host_debugfs(host);#endifmmc_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/ clockcompleted_eventsiospending_eventsregsreqstate# cat /sys/kernel/debug/mmc0/ios <clock:52000000 Hzvdd: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)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。

  •  标签:  
  • sdio